167

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;
}
ARW
  • 3,306
  • 7
  • 32
  • 41

6 Answers6

137

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.

Tim S.
  • 55,448
  • 7
  • 96
  • 122
66

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.

Mahmood Dehghan
  • 7,761
  • 5
  • 54
  • 71
16

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;
}
rr-
  • 14,303
  • 6
  • 45
  • 67
Northstrider
  • 1,149
  • 13
  • 14
8

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.

Tim
  • 5,435
  • 7
  • 42
  • 62
Matthias Meid
  • 12,455
  • 7
  • 45
  • 79
1

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.

Erix
  • 7,059
  • 2
  • 35
  • 61
-2

No it is not possible. The only way that is possible is

static void Main(string[] args)
{
    BaseClass myBaseObject = new DerivedClass();
    DerivedClass myDerivedObject = myBaseObject as DerivedClass;

    myDerivedObject.MyDerivedProperty = true;
}
Jan P.
  • 3,261
  • 19
  • 26
  • 19
    this throws a NullReferenceException, so doesn´t work as stated – Ahmed Alejo Apr 18 '16 at 16:29
  • thanks for this, the other answers didn't say how to cast – Haroen Viaene Aug 22 '16 at 16:59
  • Sometimes, a little bit of rethinking, can save from major problems. Thank you! – peter70 May 11 '17 at 06:59
  • 1
    but this doesn't work (as ahmed mentioned it throws null reference exception) – Bassie Apr 27 '18 at 00:41
  • 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. – Papa Ccompis Jul 20 '18 at 21:18
  • 2
    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. – AnthonyVO Mar 12 '21 at 00:27