Is it possible to assign a base class object to a derived class reference with an explicit typecast?

Viewed 149648

Is it possible to assign a base class object to a derived class reference with an explicit typecast in C#?.

I have tried it and it creates a run-time error.

31 Answers

No. A reference to a derived class must actually refer to an instance of the derived class (or null). Otherwise how would you expect it to behave?

For example:

object o = new object();
string s = (string) o;
int i = s.Length; // What can this sensibly do?

If you want to be able to convert an instance of the base type to the derived type, I suggest you write a method to create an appropriate derived type instance. Or look at your inheritance tree again and try to redesign so that you don't need to do this in the first place.

No, that's not possible since assigning it to a derived class reference would be like saying "Base class is a fully capable substitute for derived class, it can do everything the derived class can do", which is not true since derived classes in general offer more functionality than their base class (at least, that's the idea behind inheritance).

You could write a constructor in the derived class taking a base class object as parameter, copying the values.

Something like this:

public class Base {
    public int Data;

    public void DoStuff() {
        // Do stuff with data
    }
}

public class Derived : Base {
    public int OtherData;

    public Derived(Base b) {
        this.Data = b.Data;
        OtherData = 0; // default value
    }

    public void DoOtherStuff() {
        // Do some other stuff
    }
}

In that case you would copy the base object and get a fully functional derived class object with default values for derived members. This way you can also avoid the problem pointed out by Jon Skeet:

Base b = new Base();//base class
Derived d = new Derived();//derived class

b.DoStuff();    // OK
d.DoStuff();    // Also OK
b.DoOtherStuff();    // Won't work!
d.DoOtherStuff();    // OK

d = new Derived(b);  // Copy construct a Derived with values of b
d.DoOtherStuff();    // Now works!

Solution with JsonConvert (instead of typecast)

Today i faced the same issue and i found a simple and quick solution to the problem using JsonConvert.

var base = new BaseClass();
var json = JsonConvert.SerializeObject(base);
DerivedClass derived = JsonConvert.DeserializeObject<DerivedClass>(json);

No it is not possible, hence your runtime error.

But you can assign an instance of a derived class to a variable of base class type.

Expanding on @ybo's answer - it isn't possible because the instance you have of the base class isn't actually an instance of the derived class. It only knows about the members of the base class, and doesn't know anything about those of the derived class.

The reason that you can cast an instance of the derived class to an instance of the base class is because the derived class actually already is an instance of the base class, since it has those members already. The opposite cannot be said.

You can cast a variable that is typed as the base-class to the type of a derived class; however, by necessity this will do a runtime check, to see if the actual object involved is of the correct type.

Once created, the type of an object cannot be changed (not least, it might not be the same size). You can, however, convert an instance, creating a new instance of the second type - but you need to write the conversion code manually.

In c# 9.0 you can try to use records for this. They have default copy constructor that copy all fields - no need to use reflection / constructor with all fields.

public record BaseR
{
   public string Prop1 { get; set; }
}

public record DerivedR : BaseR
{
   public DerivedR(BaseR baseR) : base(baseR) { }
   public string Prop2 { get; set; }
}

var baseR = new BaseR { Prop1 = "base prob" };
var derivedR = new DerivedR(baseR) { Prop2 = "new prop" };

enter image description here

You have to use an object cloner/copier that will assign all the properties one by one.

Doing this by hand is inefficient and not future-proof. But serializing & deserializing to JSON and back is not the best solution, it is slow and very memory inefficient.

However, using AutoMapper is fast. PropMapper is even faster.

PS. Disclosure: I am a contributor at PropMapper open source project.

You can use an Extention:

public static void CopyOnlyEqualProperties<T>(this T objDest, object objSource) where T : class
    {
        foreach (PropertyInfo propInfo in typeof(T).GetProperties())
            if (objSource.GetType().GetProperties().Any(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()))
                propInfo.SetValue(objDest, objSource.GetType().GetProperties().First(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()).GetValue(objSource));
    }

In Code:

public class BaseClass
{
  public string test{ get; set;}
}
public Derived : BaseClass
{
//Some properies
}

public void CopyProps()
{
   BaseClass baseCl =new BaseClass();
   baseCl.test="Hello";
   Derived drv=new Derived();
   drv.CopyOnlyEqualProperties(baseCl);
   //Should return Hello to the console now in derived class.
   Console.WriteLine(drv.test);

}

Not in the Traditional Sense... Convert to Json, then to your object, and boom, done! Jesse above had the answer posted first, but didn't use these extension methods which make the process so much easier. Create a couple of extension methods:

    public static string ConvertToJson<T>(this T obj)
    {
        return JsonConvert.SerializeObject(obj);
    }
    public static T ConvertToObject<T>(this string json)
    {
        if (string.IsNullOrEmpty(json))
        {
            return Activator.CreateInstance<T>();
        }
        return JsonConvert.DeserializeObject<T>(json);
    }

Put them in your toolbox forever, then you can always do this:

var derivedClass = baseClass.ConvertToJson().ConvertToObject<derivedClass>();

Ah, the power of JSON.

There are a couple of gotchas with this approach: We really are creating a new object, not casting, which may or may not matter. Private fields will not be transferred, constructors with parameters won't be called, etc. It is possible that some child json won't be assigned. Streams are not innately handled by JsonConvert. However, if our class doesn't rely on private fields and constructors, this is a very effective method of moving data from class to class without mapping and calling constructors, which is the main reason why we want to cast in the first place.

I know this is old but I've used this successfully for quite a while.

   private void PopulateDerivedFromBase<TB,TD>(TB baseclass,TD derivedclass)
    {
        //get our baseclass properties
        var bprops = baseclass.GetType().GetProperties();
        foreach (var bprop in bprops)
        {
            //get the corresponding property in the derived class
            var dprop = derivedclass.GetType().GetProperty(bprop.Name);
            //if the derived property exists and it's writable, set the value
            if (dprop != null && dprop.CanWrite)
                dprop.SetValue(derivedclass,bprop.GetValue(baseclass, null),null);
        }
    } 

I combined some portions of the previous answers (thanks to those authors) and put together a simple static class with two methods that we're using.

Yes, it's simple, no it doesn't cover all scenarios, yes it could be expanded and made better, no it's not perfect, yes it could possibly be made more efficient, no it's not the greatest thing since sliced bread, yes there are full-on robust nuget package object mappers out there that are way better for heavy use, etc etc, yada yada - but it works for our basic needs though :)

And of course it will try to map values from any object to any object, derived or not (only the public properties that are named the same of course - ignores the rest).

USAGE:

SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };

// creates new object of type "RealPerson" and assigns any matching property 
// values from the puppet object 
// (this method requires that "RealPerson" have a parameterless constructor )
RealPerson person = ObjectMapper.MapToNewObject<RealPerson>(puppet);

// OR

// create the person object on our own 
// (so RealPerson can have any constructor type that it wants)
SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };
RealPerson person = new RealPerson("tall") {Name = "Steve"};

// maps and overwrites any matching property values from 
// the puppet object to the person object so now our person's age will get set to 5 and
// the name "Steve" will get overwritten with "Elmo" in this example
ObjectMapper.MapToExistingObject(puppet, person);

STATIC UTILITY CLASS:

public static class ObjectMapper
{
    // the target object is created on the fly and the target type 
    // must have a parameterless constructor (either compiler-generated or explicit) 
    public static Ttarget MapToNewObject<Ttarget>(object sourceobject) where Ttarget : new()
    {
        // create an instance of the target class
        Ttarget targetobject = (Ttarget)Activator.CreateInstance(typeof(Ttarget));

        // map the source properties to the target object
        MapToExistingObject(sourceobject, targetobject);

        return targetobject;
    }

    // the target object is created beforehand and passed in
    public static void MapToExistingObject(object sourceobject, object targetobject)
    {
        // get the list of properties available in source class
        var sourceproperties = sourceobject.GetType().GetProperties().ToList();

        // loop through source object properties
        sourceproperties.ForEach(sourceproperty => {

            var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);

            // check whether that property is present in target class and is writeable
            if (targetProp != null && targetProp.CanWrite)
            {
                // if present get the value and map it
                var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
                targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
            }
        });
    }
}

You can use a copy constructor that immediately invokes the instance constructor, or if your instance constructor does more than assignments have the copy constructor assign the incoming values to the instance.

class Person
{
    // Copy constructor 
    public Person(Person previousPerson)
    {
        Name = previousPerson.Name;
        Age = previousPerson.Age;
    }

    // Copy constructor calls the instance constructor.
    public Person(Person previousPerson)
        : this(previousPerson.Name, previousPerson.Age)
    {
    }

    // Instance constructor.
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public int Age { get; set; }

    public string Name { get; set; }
}

Referenced the Microsoft C# Documentation under Constructor for this example having had this issue in the past.

With regarding @MarkusKnappenJohansson answer and below comments we can change his code extending extension function :) so it may update an existing deriving class instance via this code :

 public static TDerived As<TDerived>(this Base baseInstance, TDerived updateDerivedInstance = null) where TDerived : Base, new()
    {
        Type baseType = typeof(Base);
        Type derivedType = typeof(TDerived);

        PropertyInfo[] properties = baseType.GetProperties();
        object instanceDerived = null;

        if (updateDerivedInstance == null)
        {
            instanceDerived = Activator.CreateInstance(derivedType);             
        }
        else
        {
            instanceDerived = (object)(updateDerivedInstance);
        }

        foreach (PropertyInfo property in properties)
        {
            if (property.CanWrite)
            {
                property.SetValue(instanceDerived, property.GetValue(baseInstance, null), null);
            }
        }

        return (TDerived)instanceDerived;
    }

Usage for getting new derived Instance is var base = new Base(); base.Data = 1; var derived = base.As<Derived>(); Console.Write(derived.Data); // Would output 1

Usage for updating existing derived Instance is var derived = new Derived(); var base = new Base(); base.Data = 1; var derivedUpdated = base.As<Derived>(derived); Console.Write(derivedUpdated.Data); // Would output 1

How about:

public static T As<T>(this object obj)
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
    }

Best way to add all base properties to derived item is use reflection in costructor. Try this code, without creating methods or instances.

    public Derived(Base item) :base()
    {

        Type type = item.GetType();

        System.Reflection.PropertyInfo[] properties = type.GetProperties();
        foreach (var property in properties)
        {
            try
            {
                property.SetValue(this, property.GetValue(item, null), null);
            }
            catch (Exception) { }
        }

    }

I disagree that it is not possible. You can do it like this:

public class Auto 
{ 
    public string Make {get; set;}
    public string Model {get; set;}
}

public class Sedan : Auto
{ 
    public int NumberOfDoors {get; set;}
}

public static T ConvertAuto<T>(Sedan sedan) where T : class
{
    object auto = sedan;
    return (T)loc;
}

Usage:

var sedan = new Sedan();
sedan.NumberOfDoors = 4;
var auto = ConvertAuto<Auto>(sedan);

This is how I solved this for fields. You can do the same iteration through properties if you want. You may want to do some checks for null etc. but this is the idea.

 public static DerivedClass ConvertFromBaseToDerived<BaseClass, DerivedClass>(BaseClass baseClass)
            where BaseClass : class, new()
            where DerivedClass : class, BaseClass, new()
        {
            DerivedClass derived = (DerivedClass)Activator.CreateInstance(typeof(DerivedClass));
            derived.GetType().GetFields().ToList().ForEach(field =>
            {
                var base_ = baseClass.GetType().GetField(field.Name).GetValue(baseClass);
                field.SetValue(derived, base_);

            });

            return derived;
        }

You can just serialize the base object to JSON and then deserialize it to the derived object.

No, see this question which I asked - Upcasting in .NET using generics

The best way is to make a default constructor on the class, construct and then call an Initialise method

You can't cast directly, but you can cast it using an extension method as below.

public static T CastObject<T>(this object obj) where T : new()
    {
        PropertyInfo[] properties = typeof(T).GetProperties();
        List<string> source = (from x in obj.GetType().GetProperties()
                               select x.Name).ToList();
        T val = new T();
        PropertyInfo[] array = properties;
        foreach (PropertyInfo prop in array)
        {
            if (source.Any((string x) => x == prop.Name))
            {
                prop.SetValue(val, prop.GetValue(obj));
            }
        }
        return val;
    }

So you can call this extension method to your base class object.

YourBaseClassObjectInstance.CastObject<YourDerivedClassObjectType>()

Note: This extension method is for your base class INSTANCE. Not for your base class TYPE. Likewise, the second parameter is derived class TYPE not derived class INSTANCE.

Related