I am trying to cast from a parent class to a child class but I get an InvalidCastException. The child class only has one property of type int. Does anyone know what I need to do?
A simple way to downcast in C# is to serialize the parent and then deserialize it into the child.
var serializedParent = JsonConvert.SerializeObject(parentInstance);
Child c = JsonConvert.DeserializeObject<Child>(serializedParent);
I have a simple console app that casts animal into dog, using the above two lines of code over here
You can't cast a mammal into a dog - it might be a cat.
You can't cast a food into a sandwich - it might be a cheeseburger.
You can't cast a car into a Ferrari - it might be a Honda, or more specifically, You can't cast a Ferrari 360 Modena to a Ferrari 360 Challange Stradale - there are differnt parts, even though they are both Ferrari 360s.
The instance that your base class reference is referring to is not an instance of your child class. There's nothing wrong.
More specifically:
Base derivedInstance = new Derived();
Base baseInstance = new Base();
Derived good = (Derived)derivedInstance; // OK
Derived fail = (Derived)baseInstance; // Throws InvalidCastException
For the cast to be successful, the instance that you're downcasting must be an instance of the class that you're downcasting to (or at least, the class you're downcasting to must be within the instance's class hierarchy), otherwise the cast will fail.
I have seen most of the people saying explicit parent to child casting is not possible, that actually is not true. Let's take a revised start and try proving it by examples.
As we know in .net all castings have two broad categories.
- For Value type
- For Reference type (in your case its reference type)
Reference type has further three main situational cases in which any scenario can lie.
Child to Parent (Implicit casting - Always successful)
Case 1. Child to any direct or indirect parent
Employee e = new Employee();
Person p = (Person)e; //Allowed
Parent to Child (Explicit casting - Can be successful)
Case 2. Parent variable holding parent object (Not allowed)
Person p = new Person(); // p is true Person object
Employee e = (Employee)p; //Runtime err : InvalidCastException <-------- Yours issue
Case 3. Parent variable holding child object (Always Successful)
Note: Because objects has polymorphic nature, it is possible for a variable of a parent class type to hold a child type.
Person p = new Employee(); // p actually is Employee
Employee e = (Employee)p; // Casting allowed
Conclusion : After reading above all, hope it will make sense now like how parent to child conversion is possible(Case 3).
Answer To The Question :
Your answer is in case 2.Where you can see such casting is not allowed by OOP and you are trying to violate one of OOP's basic rule.So always choose safe path.
Further more, to avoid such exceptional situations .net has recommended using is/as operators those will help you to take informed decisions and provide safe casting.
There are some cases when such a cast would make sense.
I my case, I was receiving a BASE class over the network, and I needed more features to it.
So deriving it to handle it on my side with all the bells and whistles I wanted, and casting the received BASE class into the DERIVED one was simply not an option (Throws InvalidCastException of Course)
One practical think-out-of-the-box SOLUTION was to declare an EXTENSION Helper class that was NOT inheriting BASE class actually, but INCLUDING IT as a member.
public class BaseExtension
{
Base baseInstance;
public FakeDerived(Base b)
{
baseInstance = b;
}
//Helper methods and extensions to Base class added here
}
If you have loose coupling and just need a couple of extra features to base class without REALLY having an absolute need of derivation, that could be a quick and simple workaround.
BaseExtension
here to at least implement IBase
such that you can use it in similar contexts? Or wasn't important for your needs? –
Acotyledon That would violate object oriented principles. I'd say an elegant solution here and elsewhere in the project is using a object mapping framework like AutoMapper to configure a projection.
Here's a slighty more complex configuration than is neccessary but is flexible enough for most cases:
public class BaseToChildMappingProfile : Profile
{
public override string ProfileName
{
get { return "BaseToChildMappingProfile"; }
}
protected override void Configure()
{
Mapper.CreateMap<BaseClass, ChildClassOne>();
Mapper.CreateMap<BaseClass, ChildClassTwo>();
}
}
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<BaseToChildMappingProfile>();
});
}
}
When application starts call AutoMapperConfiguration.Configure()
and then you can project like this:
ChildClassOne child = Mapper.Map<BaseClass, ChildClassOne>(baseClass);
Properties are mapped by convention so if the class is inherited the property names are exactly the same and mapping is configured automatically. You can add additional properties by tweaking the configuration. See the documentation .
Paul, you didn't ask 'Can I do it' - I am assuming you want to know how to do it!
We had to do this on a project - there are many of classes we set up in a generic fashion just once, then initialize properties specific to derived classes. I use VB so my sample is in VB (tough noogies), but I stole the VB sample from this site which also has a better C# version:
Sample code:
Imports System
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Text
Imports System.Diagnostics
Module ClassUtils
Public Sub CopyProperties(ByVal dst As Object, ByVal src As Object)
Dim srcProperties() As PropertyInfo = src.GetType.GetProperties
Dim dstType = dst.GetType
If srcProperties Is Nothing Or dstType.GetProperties Is Nothing Then
Return
End If
For Each srcProperty As PropertyInfo In srcProperties
Dim dstProperty As PropertyInfo = dstType.GetProperty(srcProperty.Name)
If dstProperty IsNot Nothing Then
If dstProperty.PropertyType.IsAssignableFrom(srcProperty.PropertyType) = True Then
dstProperty.SetValue(dst, srcProperty.GetValue(src, Nothing), Nothing)
End If
End If
Next
End Sub
End Module
Module Module1
Class base_class
Dim _bval As Integer
Public Property bval() As Integer
Get
Return _bval
End Get
Set(ByVal value As Integer)
_bval = value
End Set
End Property
End Class
Class derived_class
Inherits base_class
Public _dval As Integer
Public Property dval() As Integer
Get
Return _dval
End Get
Set(ByVal value As Integer)
_dval = value
End Set
End Property
End Class
Sub Main()
' NARROWING CONVERSION TEST
Dim b As New base_class
b.bval = 10
Dim d As derived_class
'd = CType(b, derived_class) ' invalidcast exception
'd = DirectCast(b, derived_class) ' invalidcast exception
'd = TryCast(b, derived_class) ' returns 'nothing' for c
d = New derived_class
CopyProperties(d, b)
d.dval = 20
Console.WriteLine(b.bval)
Console.WriteLine(d.bval)
Console.WriteLine(d.dval)
Console.ReadLine()
End Sub
End Module
Of course this isn't really casting. It's creating a new derived object and copying the properties from the parent, leaving the child properties blank. That's all I needed to do and it sounds like its all you need to do. Note it only copies properties, not members (public variables) in the class (but you could extend it to do that if you are for shame exposing public members).
Casting in general creates 2 variables pointing to the same object (mini tutorial here, please don't throw corner case exceptions at me). There are significant ramifications to this (exercise to the reader)!
Of course I have to say why the languague doesn't let you go from base to derive instance, but does the other way. imagine a case where you can take an instance of a winforms textbox (derived) and store it in a variable of type Winforms control. Of course the 'control' can move the object around OK and you can deal with all the 'controll-y' things about the textbox (e.g., top, left, .text properties). The textbox specific stuff (e.g., .multiline) can't be seen without casting the 'control' type variable pointing to the textbox in memory, but it's still there in memory.
Now imagine, you have a control, and you want to case a variable of type textbox to it. The Control in memory is missing 'multiline' and other textboxy things. If you try to reference them, the control won't magically grow a multiline property! The property (look at it like a member variable here, that actually stores a value - because there is on in the textbox instance's memory) must exist. Since you are casting, remember, it has to be the same object you're pointing to. Hence it is not a language restriction, it is philosophically impossible to case in such a manner.
The instance of the object should be created using the child class's type, you can't cast a parent type instance to a child type
As of C# 7.0, you can use the is keyword to do this :
With those class defined :
class Base { /* Define base class */ }
class Derived : Base { /* Define derived class */ }
You can then do somehting like :
void Funtion(Base b)
{
if (b is Derived d)
{
/* Do something with d which is now a variable of type Derived */
}
}
Which would be equivalent to :
void Funtion(Base b)
{
Defined d;
if (b is Derived)
{
d = (Defined)b;
/* Do something with d */
}
}
You could now call :
Function(new Derived()); // Will execute code defined in if
As well as
Function(new Base()); // Won't execute code defined in if
That way you can be sure that your downcast will be valid and won't throw an exception !
As for me it was enough to copy all property fields from the base class to the parent like this:
using System.Reflection;
public static ChildClass Clone(BaseClass b)
{
ChildClass p = new ChildClass(...);
// Getting properties of base class
PropertyInfo[] properties = typeof(BaseClass).GetProperties();
// Copy all properties to parent class
foreach (PropertyInfo pi in properties)
{
if (pi.CanWrite)
pi.SetValue(p, pi.GetValue(b, null), null);
}
return p;
}
An universal solution for any object can be found here
To cast, the actual object must be of a Type equal to or derived from the Type you are attempting to cast to...
or, to state it in the opposite way, the Type you are trying to cast it to must be the same as, or a base class of, the actual type of the object.
if your actual object is of type Baseclass, then you can't cast it to a derived class Type...
A variation on the serialization approach for those using ServiceStack:
var child = baseObject.ConvertTo<ChildType>();
or the more verbose:
var child = baseObject.ToJson().FromJson<ChildType>();
ServiceStack's serialization might be super fast and all, but clearly, this is not a solution for massive conversions in low-latency transfers, nor for highly complex types. That's likely obvious to anyone using ServiceStack, but thought I'd clarify in anticipation of comments.
You can use derived class constructor with base class parameter.
class Base
{
public int Id { get; }
public string Name { get; }
public Base(Base baseClass)
{
Id = baseClass.Id;
Name = baseClass.Name;
}
public Base(int id, string name)
{
Id = id;
Name = name;
}
}
class Child : Base
{
public string UniqueId { get; set; }
public Child(Base baseClass) : base(baseClass) { }
}
Example of using:
Base realBase = new Base(1, "Base");
Child realChild = new Child(realBase);
© 2022 - 2024 — McMap. All rights reserved.