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

33

116

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.

Mikkimiko answered 8/4, 2009 at 11:12 Comment(0)
C
114

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.

Cess answered 8/4, 2009 at 11:15 Comment(18)
@Mike: The code compiles just fine. It falls over at execution time though :)Cess
Then what exactly happens when we write Base b= new Derived(); ? Will it create objects for both base and derived class?Scale
@Akie: No, it creates a single object of type Derived, but you can treat a Derived reference as a Base reference.Cess
So Is there any difference in resulting object for these two statements? Base b = new Base() and Base b = new Derived()? what is the benefit of using one over other?Scale
@Akie: Yes, one creates an instance of Base, and the other creates an instance of Derived. If you call a virtual method on b which was overridden in Derived, you'll see the Derived behaviour if you've got an instance of Derived. But it's not really appropriate to go into the details in a Stack Overflow comment thread - you should really read a good C# book or tutorial, as this is pretty fundamental stuff.Cess
Very well. Understood at some extent. Thanks for your explaination. Have an nice day.Scale
@JonSkeet I know it's a pretty old post, but I was wondering what's the reason why it's not a compile error? Is there any reason for this? Would be nice if you could answer, even though its old.Bergama
@RandRandom: That would require the compiler to keep track of possible types of the actual value, compared with the declared type of the variable. Getting multiple compilers to do so consistently in all scenarios - and doing so without making the language specification incredibly convoluted - would be very hard.Cess
There are cases when conversions between types make sense. C# supports the conversion operators, but artificially disables it when the destination type has is descendant of the source type. There are cases where such conversion would make sense too. The Op has stumbled on that C# limitation.Newfashioned
@Ark-kun: There are cases where it would be useful, but it would also be confusing due to an implicit conversion already existing.Cess
Just like when it's doing Widening or Narrowing conversions of numeric Types at Runtime, ideally the language should check if it's able to perform convert from Base to Derived Class or vice versa w/o changing or copying data. In fact, it should be easier, cuz it should be able to do it at Compile Time, cuz all it needs is to check if either Class has more Variables or Auto-implemented Properties. If the only difference is more / less non-Auto-implemented Properties and Methods, then you only get to access what the target Class has after the Assignment.Leonialeonid
The use case I wanted this for was where I was just trying to rename a Class defined in a Library I can't change. So my Derived Class was empty, no Variables, Auto-/Manual-Implemented Properties or Methods - nothing. Any, "'smart'" Compiler, "'should'" know there's no reason not to allow the conversion between those particular Base and Derived Classes.Leonialeonid
@Tom: No, absolutely not. It would break expectations all over the place. If I have a variable Foo foo where Foo is a class, then foo is Foo should evaluate to true every time foo is non-null, for example. That wouldn't be the case in your code. Your use case is trying to abuse inheritance, IMO. Everything is behaving exactly as per the specification, and I'm glad it's specified that way.Cess
Umm, no. All I'm saying is (if Base and Derived Classes differ only by non-Auto-implemented Properties and Methods, if even), to allow "Base b = new Base(); Derived d = new Derived; d = (Base) b;" (or something like d = Derived.ConvertFrom<Base>(b)). Just like after any conversion, the Type of the target Variable does not change, d is Derived would (or at least "'should'" after whatever Compiler-generated code for the conversion is executed) still be true. I'm not saying it has to be no data manipulation whatsoever (like typecasting in Borland Pascal and maybe C).Leonialeonid
@Tom: How could d is Derived be true? If you call d.GetType() it would return Base, because that's the type of the object. If you're saying it wouldn't return Base, then we're into whole realms of oddness, IMO.Cess
Maybe so, but your prior statement that given Foo foo where Foo is a Class, then foo is Foo should == true every time foo is non-null is not the "whole truth" even with C# as currently specified. If I do Base b = new Base(); Derived d = new Derived(); b = d;, yes, b is Base still == true, but then again, now, so is 'b is Derived` and 'b.GetType()` now == Derived vs. Base and the whole time, both d is Derived and d is Base == true.Leonialeonid
@Tom: Yes, but that's where the actual object is an instance of Derived. You're talking about a case where the actual object is an instance of Base, not Derived, but d is Derived would still evaluate to true? Sorry, that just makes no sense to me.Cess
If you choose to use a copy constructor you can have it immediately invoke your constructor, or do the assignment directly in the copy constructor - https://mcmap.net/q/54108/-is-it-possible-to-assign-a-base-class-object-to-a-derived-class-reference-with-an-explicit-typecastWhilom
P
57

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!
Portis answered 8/4, 2009 at 11:36 Comment(0)
K
30

Solution with JsonConvert

Although strictly speaking, it is a no. You can use this "hacky" but simple and quick solution using JsonConvert.

var base = new BaseClass();
var json = JsonConvert.SerializeObject(base);
DerivedClass derived = JsonConvert.DeserializeObject<DerivedClass>(json);
Kermit answered 16/6, 2019 at 15:47 Comment(5)
I answered this again below with extension methods. Yes, this is the answer.Piegari
public static T ConvertObject<T>(this object myobj) { return Newtonsoft.Json.JsonConvert.DeserializeObject<T> Newtonsoft.Json.JsonConvert.SerializeObject(myobj)); }Brilliancy
If Derived Class's has JsonRequired fields or JsonProperty that it for set PropertyName, it will not correct workingPskov
GENIUS!!! This is a great answer, Thanks!Ricoricochet
Depending of the properties It can cause errors likeNewtonsoft.Json.JsonSerializationException: Self referencing loop detected for property. Consider to pass new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize };Fronia
D
25

I had this problem and solved it by adding a method that takes a type parameter and converts the current object into that type.

public TA As<TA>() where TA : Base
{
    var type = typeof (TA);
    var instance = Activator.CreateInstance(type);

     PropertyInfo[] properties = type.GetProperties();
     foreach (var property in properties)
     {
         property.SetValue(instance, property.GetValue(this, null), null);
     }

     return (TA)instance;
}

That means that you can use it in you code like this:

var base = new Base();
base.Data = 1;
var derived = base.As<Derived>();
Console.Write(derived.Data); // Would output 1
Durgy answered 3/5, 2014 at 14:43 Comment(2)
You should use the type of the current class (base class) to get and set properties since those are the values you want to map over to the derived class.Halfon
If you have properties that can't be written to in the derived type you should probably change to: if (property.CanWrite) property.SetValue(instance, property.GetValue(this, null), null);Adit
C
11

As many others have answered, No.

I use the following code on those unfortunate occasions when I need to use a base type as a derived type. Yes it is a violation of the Liskov Substitution Principle (LSP) and yes most of the time we favor composition over inheritance. Props to Markus Knappen Johansson whose original answer this is based upon.

This code in the base class:

    public T As<T>()
    {
        var type = typeof(T);
        var instance = Activator.CreateInstance(type);

        if (type.BaseType != null)
        {
            var properties = type.BaseType.GetProperties();
            foreach (var property in properties)
                if (property.CanWrite)
                    property.SetValue(instance, property.GetValue(this, null), null);
        }

        return (T) instance;
    }

Allows:

    derivedObject = baseObect.As<derivedType>()

Since it uses reflection, it is "expensive". Use accordingly.

Caril answered 17/9, 2016 at 6:30 Comment(3)
I just tried this, and figured, it could be improved further, by overloading the explicit operator (and the implicit operator as well) .. but - the Compiler won't allow it: user-defined conversions to or from a base class are not allowed I see the reasons for this, but am disappointed, as it would have been so much fun if it did allow this..Considering
@MEC: I noticed you dropped the ` where T : MyBaseClass` part and added the if (type.BaseType != null) Statement relative to Markus Knappen Johansson 's A. Why is that? That means it would allow a Type in the Calls that's not Derived from MyBaseClass (or anything for that matter). I realize it'll still cause a compiler error if Assigned to myDerivedObject, but if it's just used as a Expression, it'll compile and at run-time just create a myDerivedObject without any data copied from "myBaseObject". I can't imagine an use case for that.Leonialeonid
@Tom, late reply, but thought it might still be useful. The best response to your question probably would be to say that the name "As" would better have been "AsOrDefault". Essentially we can take this result and compare it to a Default such as we do when using Linq's SingleOrDefault or FirstOrDefault.Caril
B
7

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.

Bygone answered 8/4, 2009 at 11:14 Comment(0)
B
6

As everyone here said, that's not possible directly.

The method I prefer and is rather clean, is to use an Object Mapper like AutoMapper.

It will do the task of copying properties from one instance to another (Not necessarily the same type) automatically.

Besetting answered 7/1, 2013 at 20:36 Comment(0)
H
6

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

Heraclitean answered 13/1, 2021 at 10:16 Comment(0)
P
4

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.

Piegari answered 25/6, 2020 at 21:57 Comment(5)
This does not do what OP asked. What you're doing is constructing a new object of the correct type for the variable, using data from the original object of the wrong type. This may or may not work, but either way, it is certainly not assigning an object of the base class type to a variable of the derived type.Ahner
I answered the question: Is it possible to assign a base class object to a derived class reference with an explicit typecast? By saying no. I am providing an alternative that absolutely does work and is less confusing than generics. As denoted numerous times above, it can cause issues assigning to a derived class properties from a base class, however, this is exactly how it would work (and does in apis) if it were possible. Just because my answer can be used from a "wrong" type doesn't mean it cannot be used for a "right" type. @LasseV.Karlsen please retract your negative rating.Piegari
Unlike most of the answers here that daisy chain JsonConverts, I show how to handle null as well.Piegari
Great addition to catch some edge cases :DKermit
Just FYI, If you are using entity framework, you may have issues with converting to JSON. This may be because there is a circular reference due to virtual table references. If those child models also have a virtual reference to the parent, you can see where the circular reference exists. I figured since I gave a few gotchas, I'd append this one.Piegari
I
3

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.

Ikey answered 8/4, 2009 at 11:16 Comment(0)
R
3

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.

Remind answered 8/4, 2009 at 11:17 Comment(0)
A
3

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.

Anett answered 11/10, 2021 at 21:40 Comment(0)
B
2

No, it is not possible.

Consider a scenario where an ACBus is a derived class of base class Bus. ACBus has features like TurnOnAC and TurnOffAC which operate on a field named ACState. TurnOnAC sets ACState to on and TurnOffAC sets ACState to off. If you try to use TurnOnAC and TurnOffAC features on Bus, it makes no sense.

Buttocks answered 25/8, 2014 at 11:9 Comment(0)
B
2
class Program
{
    static void Main(string[] args)
    {
        a a1 = new b();  
        a1.print();  
    }
}
class a
{
    public a()
    {
        Console.WriteLine("base class object initiated");
    }
    public void print()
    {
        Console.WriteLine("base");
    }
}
class b:a
{
    public b()
    {
        Console.WriteLine("child class object");
    }
    public void print1()
    {
        Console.WriteLine("derived");
    }
}

}

when we create a child class object,the base class object is auto initiated so base class reference variable can point to child class object.

but not vice versa because a child class reference variable can not point to base class object because no child class object is created.

and also notice that base class reference variable can only call base class member.

Bottali answered 11/9, 2016 at 15:22 Comment(0)
S
2

There actually IS a way to do this. Think about how you might use Newtonsoft JSON to deserialize an object from json. It will (or at least can) ignore missing elements and populate all the elements that it does know about.

So here's how I did it. A small code sample will follow my explanation.

  1. Create an instance of your object from the base class and populate it accordingly.

  2. Using the "jsonconvert" class of Newtonsoft json, serialize that object into a json string.

  3. Now create your sub class object by deserializing with the json string created in step 2. This will create an instance of your sub class with all the properties of the base class.

This works like a charm! So.. when is this useful? Some people asked when this would make sense and suggested changing the OP's schema to accommodate the fact that you can't natively do this with class inheritance (in .Net).

In my case, I have a settings class that contains all the "base" settings for a service. Specific services have more options and those come from a different DB table, so those classes inherit the base class. They all have a different set of options. So when retrieving the data for a service, it's much easier to FIRST populate the values using an instance of the base object. One method to do this with a single DB query. Right after that, I create the sub class object using the method outlined above. I then make a second query and populate all the dynamic values on the sub class object.

The final output is a derived class with all the options set. Repeating this for additional new sub classes takes just a few lines of code. It's simple, and it uses a very tried and tested package (Newtonsoft) to make the magic work.

This example code is vb.Net, but you can easily convert to c#.

' First, create the base settings object.
    Dim basePMSettngs As gtmaPayMethodSettings = gtmaPayments.getBasePayMethodSetting(payTypeId, account_id)
    Dim basePMSettingsJson As String = JsonConvert.SerializeObject(basePMSettngs, Formatting.Indented)

    ' Create a pmSettings object of this specific type of payment and inherit from the base class object
    Dim pmSettings As gtmaPayMethodAimACHSettings = JsonConvert.DeserializeObject(Of gtmaPayMethodAimACHSettings)(basePMSettingsJson)
Storz answered 7/5, 2017 at 12:44 Comment(1)
using C# and Newtonsoft.Json: var destObject = JsonConvert.DeserializeObject<DestinationType>(JsonConvert.SerializeObject(srcObject));. I would only use this for unit tests and other non-production "hacking"!Penn
J
2

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);

}
Jacy answered 27/4, 2018 at 17:13 Comment(0)
P
1

Might not be relevent, but I was able to run code on a derived object given its base. It's definitely more hacky than I'd like, but it works:

public static T Cast<T>(object obj)
{
    return (T)obj;
}

...

//Invoke parent object's json function
MethodInfo castMethod = this.GetType().GetMethod("Cast").MakeGenericMethod(baseObj.GetType());
object castedObject = castMethod.Invoke(null, new object[] { baseObj });
MethodInfo jsonMethod = baseObj.GetType ().GetMethod ("ToJSON");
return (string)jsonMethod.Invoke (castedObject,null);
Poirer answered 25/11, 2015 at 4:12 Comment(0)
C
1

You can do this using generic.

public class BaseClass
{
    public int A { get; set; }
    public int B { get; set; }
    private T ConvertTo<T>() where T : BaseClass, new()
    {
         return new T
         {
             A = A,
             B = B
         }
    }

    public DerivedClass1 ConvertToDerivedClass1()
    {
         return ConvertTo<DerivedClass1>();
    }

    public DerivedClass2 ConvertToDerivedClass2()
    {
         return ConvertTo<DerivedClass2>();
    }
}

public class DerivedClass1 : BaseClass
{
    public int C { get; set; }
}

public class DerivedClass2 : BaseClass
{
    public int D { get; set; }
}

You get three benefits using this approach.

  1. You are not duplicating the code
  2. You are not using reflection (which is slow)
  3. All of your conversions are in one place
Chane answered 19/7, 2017 at 13:55 Comment(0)
M
1

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);
        }
    } 
Milesmilesian answered 25/7, 2018 at 0:46 Comment(0)
T
1

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);
            }
        });
    }
}
Tours answered 18/9, 2018 at 17:32 Comment(0)
W
1

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.

Whilom answered 14/12, 2019 at 17:29 Comment(0)
B
1

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

Below answered 9/11, 2021 at 12:9 Comment(0)
N
0

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

Not only explicit, but also implicit conversions are possible.

C# language doesn't permit such conversion operators, but you can still write them using pure C# and they work. Note that the class which defines the implicit conversion operator (Derived) and the class which uses the operator (Program) must be defined in separate assemblies (e.g. the Derived class is in a library.dll which is referenced by program.exe containing the Program class).

//In library.dll:
public class Base { }

public class Derived {
    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Implicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }

    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Explicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }
}

//In program.exe:
class Program {
    static void Main(string[] args) {
        Derived z = new Base(); //Visual Studio can show squiggles here, but it compiles just fine.
    }
}

When you reference the library using the Project Reference in Visual Studio, VS shows squiggles when you use the implicit conversion, but it compiles just fine. If you just reference the library.dll, there are no squiggles.

Newfashioned answered 16/4, 2013 at 17:2 Comment(11)
What black magic is this?!? Also, how does "Derived z = new Base()" help me do "BaseCls baseObj; DerivedCls derivedObj; derivedObj = (DerivedCls) baseObj" (the OP's Q)? Also, what does System.Runtime.CompilerServices.SpecialName Attribute do? The docs for every version from the earliest available (2.0) to "current version" (4.6? "anyone? anyone?") don't say what it does, but do say "The SpecialNameAttribute class is not currently used in the .NET Framework, but is reserved for future use.". See: [link] (msdn.microsoft.com/en-us/library/ms146064(v=vs.100).aspx).Leonialeonid
>"What black magic is this?!?" That's called .Net Framework (CLR, IL, BCL). The feature set of IL, C# and VB languages are not the same. There are features in VB that C# does not support. There are features in IL that C# does not support. There are restrictions in C# that are rather arbitrary and do not exist in underlying IL (like where T : Delegate or parametrized properties a.k.a. indexers etc etc etc).Newfashioned
>"Also, how does "Derived z = new Base()" help me do "BaseCls baseObj; DerivedCls derivedObj; derivedObj = (DerivedCls) baseObj" (the OP's Q)?" It just does. It solves the OP's question. And you do not even need the explicit cast.Newfashioned
>what does System.Runtime.CompilerServices.SpecialName Attribute do? - It's used to mark the methods produced by some special convenience constructs of the high-level .Net languages: property accessors, event accessors, constructors, operators, indexers, etc. Unless the IL method is marked with specialname it wouldn't be seen as property/event/constructor and it would just be recognized as a normal method. Manually marking appropriately-named methods with this attribute is just manually doing a bit of the compiler's job.Newfashioned
VB.Net has power operator. C# does not. How would you overload a power operator in C# for use in VB.Net? Just define an op_Exponent method and mark it with the specialname attribute.Newfashioned
>The SpecialNameAttribute class is not currently used in the .NET Framework - It's actually heavily used by the C# compile. Your compiled C# code has lots of methods marked with it.Newfashioned
Mmmmkay, that went over my head. Anyways, I tried it and (amazingly) it works - and it's still black magic to me. BUT - I just realized all of that is irrelevant because it does not answer the OP's question (in the affirmative). It was just a whole bunch of hoops to make new Base() be an alias for new Derived() as in the Object created does not contain anything that's in the Base Class!?!Leonialeonid
And your example of Derived z = new Base(); is not what the OP's wanting.The OP wants Base base = new Base(); Derived z = base; with the ability to reference, via z, non-private Variables and Properties in Base that are not Overridden / Hidden by Derived.Leonialeonid
Oops! I forgot to makeDerived Inherit from Base. It's not just making new Base() be an alias for new Derived(). HOWEVER, I noticed if I do Base base = new Base(); base.BaseStr = "1"; Derived derived = base;, derived.BaseStr != "1"!?! It == whatever its Default Value was!?! THAT is not what the OP wanted. AND, a subsequent derived.BaseStr = "2"; derived.DerivedStr = "d1"; base = (Derived) derived; (amazingly) resulted in base Type changing from Base to Derived w/ base now == derived!?! DAT be some black magic! AND is also not what the OP wanted.Leonialeonid
Correction: "base Type changing from Base to Derived" (after base = derived;) is not "black magic". I'd forgotten that's just normal C# (even without all your "black magic" hoops). But the rest of my prior comment still stands.Leonialeonid
@Leonialeonid Please, calm down and try to understand .Net. My answer is what the OP wanted. As for "derived.BaseStr != "1" ", ... well, duh. You need to write the real Base -> Derived conversion code in those conversion operators. Isn't that obvious? What my code does is allowing this conversion to be performed either implicitly or using the explicit cast operator.Newfashioned
R
0

Another solution is to add extension method like so:

 public static void CopyProperties(this object destinationObject, object sourceObject, bool overwriteAll = true)
        {
            try
            {
                if (sourceObject != null)
                {
                    PropertyInfo[] sourceProps = sourceObject.GetType().GetProperties();
                    List<string> sourcePropNames = sourceProps.Select(p => p.Name).ToList();
                    foreach (PropertyInfo pi in destinationObject.GetType().GetProperties())
                    {
                        if (sourcePropNames.Contains(pi.Name))
                        {
                            PropertyInfo sourceProp = sourceProps.First(srcProp => srcProp.Name == pi.Name);
                            if (sourceProp.PropertyType == pi.PropertyType)
                                if (overwriteAll || pi.GetValue(destinationObject, null) == null)
                                {
                                    pi.SetValue(destinationObject, sourceProp.GetValue(sourceObject, null), null);
                                }
                        }
                    }
                }
            }
            catch (ApplicationException ex)
            {
                throw;
            }
        }

then have a constructor in each derived class that accepts base class:

  public class DerivedClass: BaseClass
    { 
        public DerivedClass(BaseClass baseModel)
        {
            this.CopyProperties(baseModel);
        }
    }

It will also optionally overwrite destination properties if already set (not null) or not.

Ranie answered 19/1, 2015 at 12:31 Comment(0)
T
0

How about:

public static T As<T>(this object obj)
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
    }
Typify answered 15/2, 2019 at 8:20 Comment(0)
K
0

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) { }
        }

    }
Knurl answered 21/3, 2019 at 15:37 Comment(0)
G
0

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);
Geomancer answered 10/8, 2019 at 0:12 Comment(1)
var auto = is still of type sedanDegraw
C
0

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;
        }
Catharine answered 5/12, 2019 at 14:51 Comment(0)
S
0

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

Shandishandie answered 27/2, 2020 at 1:6 Comment(0)
A
0

One option I haven't seen suggested is the dark & dangerous world of unsafe pointer assignment. This probably should never be used in production (unless you really really really know what you're doing), however, I'm still adding this answer for the sake of completeness.

If the derived class has a similar memory structure (i.e. it only adds some new methods or method overloads, but not fields or auto-properties or similar) then you can use Unsafe.As<T>

using System.Runtime.CompilerServices;

class Letter
{
    public string Text { get; set; }
}

class PrintableLetter : Letter
{
    public void Print() { Console.WriteLine(Text); }
}

//usage
Letter a = new Letter();
PrintableLetter b = Unsafe.As<PrintableLetter>(a); //very dangerous, think twice!!!

P.S. This method can actually be used without any inheritance at all. You can "cast" anything to anything (as long as the storage structure of the two objects is the same).

Anett answered 6/7, 2023 at 9:14 Comment(0)
K
-1

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

Kliment answered 8/4, 2009 at 11:18 Comment(0)
T
-1

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.

Trotyl answered 12/6, 2022 at 0:37 Comment(0)
B
-1

If the performance is not an issue, you can convert it in one line, using Newtonsoft.Json library

var baseClassInstance = JObject.FromObject(derivedClassInstance ).ToObject<BaseClass>();

//where:  var derivedClassInstance = new DerivedClass(); and class DerivedClass:BaseClass {}
Bobbinet answered 7/3, 2023 at 14:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.