Convert base class to derived class

254,499

Solution 1

No, there's no built-in way to convert a class like you say. The simplest way to do this would be to do what you suggested: create a DerivedClass(BaseClass) constructor. Other options would basically come out to automate the copying of properties from the base to the derived instance, e.g. using reflection.

The code you posted using as will compile, as I'm sure you've seen, but will throw a null reference exception when you run it, because myBaseObject as DerivedClass will evaluate to null, since it's not an instance of DerivedClass.

Solution 2

That's not possible. but you can use an Object Mapper like AutoMapper

EDIT

I want to suggest a simpler object mapper: TinyMapper. AutoMapper is now very complicated to use. I don't use it anymore. TinyMapper covers most use cases and is far more simple AND super fast.

Example:

//In app startup
TinyMapper.Bind<Person, PersonDto>();

//Usage
var personDto = TinyMapper.Map<PersonDto>(person);

Example for AutoMapper (older versions I think) for the ones who still want to use it:

class A
{
    public int IntProp { get; set; }
}
class B
{
    public int IntProp { get; set; }
    public string StrProp { get; set; }
}

In global.asax or application startup:

AutoMapper.Mapper.CreateMap<A, B>();

Usage:

var b = AutoMapper.Mapper.Map<B>(a);

It's configurable via a fluent API.

Solution 3

I have found one solution to this, not saying it's the best one, but it feels clean to me and doesn't require any major changes to my code. My code looked similar to yours until I realized it didn't work.

My Base Class

public class MyBaseClass
{
   public string BaseProperty1 { get; set; }
   public string BaseProperty2 { get; set; }
   public string BaseProperty3 { get; set; }
   public string BaseProperty4 { get; set; }
   public string BaseProperty5 { get; set; }
}

My Derived Class

public class MyDerivedClass : MyBaseClass
{
   public string DerivedProperty1 { get; set; }
   public string DerivedProperty2 { get; set; }
   public string DerivedProperty3 { get; set; }
}

Previous method to get a populated base class

public MyBaseClass GetPopulatedBaseClass()
{
   var myBaseClass = new MyBaseClass();

   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...

   return myBaseClass;
}

Before I was trying this, which gave me a unable to cast error

public MyDerivedClass GetPopulatedDerivedClass()
{
   var newDerivedClass = (MyDerivedClass)GetPopulatedBaseClass();

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;
}

I changed my code as follows bellow and it seems to work and makes more sense now:

Old

public MyBaseClass GetPopulatedBaseClass()
{
   var myBaseClass = new MyBaseClass();

   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...

   return myBaseClass;
}

New

public void FillBaseClass(MyBaseClass myBaseClass)
{
   myBaseClass.BaseProperty1 = "Something"
   myBaseClass.BaseProperty2 = "Something else"
   myBaseClass.BaseProperty3 = "Something more"
   //etc...
}

Old

public MyDerivedClass GetPopulatedDerivedClass()
{
   var newDerivedClass = (MyDerivedClass)GetPopulatedBaseClass();

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;
}

New

public MyDerivedClass GetPopulatedDerivedClass()
{
   var newDerivedClass = new MyDerivedClass();

   FillBaseClass(newDerivedClass);

   newDerivedClass.UniqueProperty1 = "Some One";
   newDerivedClass.UniqueProperty2 = "Some Thing";
   newDerivedClass.UniqueProperty3 = "Some Thing Else";

   return newDerivedClass;
}

Solution 4

You can implement the conversion yourself, but I would not recommend that. Take a look at the Decorator Pattern if you want to do this in order to extend the functionality of an existing object.

Solution 5

No, there is no built in conversion for this. You'll need to create a constructor, like you mentioned, or some other conversion method.

Also, since BaseClass is not a DerivedClass, myDerivedObject will be null, andd the last line above will throw a null ref exception.

Share:
254,499
ARW
Author by

ARW

Updated on June 16, 2021

Comments

  • ARW
    ARW about 3 years

    Is it possible in C# to explicitly convert a base class object to one of it's derived classes? Currently thinking I have to create a constructor for my derived classes that accept a base class object as a parameter and copy over the property values. I don't really like this idea, so I'd like to avoid it if possible.

    This doesn't seem like it should work (object is instantiated as new base, so memory shouldn't be allocated for extra members of the derived class) but C# seems to allow me to do it:

    class BaseClass
    {
      ... some stuff ...
    }
    
    class DerivedClass : BaseClass
    {
        public bool MyDerivedProperty{ get; set; }
    }
    
    
    static void Main(string[] args)
    {
        BaseClass myBaseObject = new BaseClass();
        DerivedClass myDerivedObject = myBaseObject as DerivedClass;
    
        myDerivedObject.MyDerivedProperty = true;
    }
    
    • Erix
      Erix almost 12 years
      You're going to get a null ref exception on the last line.
    • Paul Aldred-Bann
      Paul Aldred-Bann almost 12 years
    • Seng Cheong
      Seng Cheong almost 12 years
      You should read about when it is appropriate to use "as" vs. a regular cast. If you use a cast here, C# compiler will tell you that what you're doing is wrong.
    • Sam I am says Reinstate Monica
      Sam I am says Reinstate Monica about 10 years
      I've voted to reopen because the marked "duplicate" is a completely different question. This question is about conversion, and the "duplicated" question is about casting
    • Jesse de gans
      Jesse de gans about 5 years
      The best and fastes option is to use JsonConvert you can find my answer on the original question
  • Bruno Casali
    Bruno Casali almost 10 years
    Very good! exactly I want! thx :D
  • A Khudairy
    A Khudairy over 9 years
    each time you add a property you will have to edit this. so for others readin this I suggest you think of using composition instead
  • Ahmed Alejo
    Ahmed Alejo about 8 years
    this throws a NullReferenceException, so doesn´t work as stated
  • Haroen Viaene
    Haroen Viaene almost 8 years
    thanks for this, the other answers didn't say how to cast
  • peter70
    peter70 about 7 years
    Sometimes, a little bit of rethinking, can save from major problems. Thank you!
  • Bassie
    Bassie about 6 years
    but this doesn't work (as ahmed mentioned it throws null reference exception)
  • Papa Ccompis
    Papa Ccompis almost 6 years
    This concept helped me solve an issue in my project. In my case, I didn't use the syntax "as DerivedClass". Instead, I cast the object like this DerivedClass myDerivedObject = (DerivedClass) myBaseObject; That worked for me.
  • HeonAle
    HeonAle about 5 years
    This works great but you have to initialize it first AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<A, B>());
  • Alex Klaus
    Alex Klaus almost 5 years
    Refer to the official AutoMapper Usage Guidelines published in 2019 for the DOs and DONTs in AutoMapper
  • Tomasz Chudzik
    Tomasz Chudzik over 4 years
    Starting from version 9.0 of the AutoMapper static API is no longer supported. You will need to do something like this: var configuration = new MapperConfiguration(cfg => { cfg.CreateMap<A, B>(); }); var mapper = new Mapper(configuration); var b = mapper.Map<A, B>(a); Then it is a good idea to store you configuration or mapper in your dependency container.
  • Newclique
    Newclique over 4 years
    This is excellent info. I'll add this as a tangent: I was looking for a way to use AutoMapper v 9.0+ in MVC. I ended up making a static property in Global.asax.cs and assigning the configured mapper to it during Application_Start. Hope that helps someone who maybe didn't think about this approach. In .net Core you could just have the mapper injected into your controller instances but this isn't available in the "traditional" .net framework.
  • nivs1978
    nivs1978 over 4 years
    Voodo like Automapper should generally be avoided. It uses reflection to run trough properties and is in general expensive to use, compared to other solution (like writing a.prop1=b.pro1, a.pro2=b.prop2 etc.)
  • AnthonyVO
    AnthonyVO over 3 years
    There is no conversion happening here. The base class pointer (myBaseObject) was simply set to an instance of a DerivedClass. It remains a DerivedClass from start to finish.