C# 无法从父类投射到子类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/988658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unable to Cast from Parent Class to Child Class
提问by Paul
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?
我试图从父类转换到子类,但我得到一个 InvalidCastException。子类只有一个 int 类型的属性。有谁知道我需要做什么?
采纳答案by Arcturus
A simple way to downcast in C# is to serialize the parent and then deserialize it into the child.
在 C# 中向下转换的一种简单方法是序列化父级,然后将其反序列化为子级。
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
我有蒙上动物为狗,用上面的代码两行了一个简单的控制台应用程序在这里
回答by Greg D
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.
要使转换成功,您向下转换的实例必须是您向下转换到的类的实例(或者至少,您要向下转换到的类必须在实例的类层次结构中),否则演员会失败。
回答by Charles Bretana
To cast, the actualobject must be of a Type equal to or derivedfromthe 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...
如果您的实际对象是Baseclass类型,那么您不能将其转换为派生类 Type...
回答by FastAl
Paul, you didn't ask 'Can I do it' - I am assuming you want to know howto 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:
我们必须在一个项目中这样做——有许多类我们以通用方式设置了一次,然后初始化特定于派生类的属性。我使用 VB,所以我的示例在 VB 中(tough noogies),但我从这个站点偷了 VB 示例,它也有一个更好的 C# 版本:
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)!
转换通常会创建 2 个指向同一个对象的变量(这里的迷你教程,请不要向我抛出极端情况异常)。对此有重大影响(读者练习)!
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.
当然我不得不说为什么语言不让你从基础到派生实例,而是以另一种方式。想象一个案例,您可以获取一个 winforms 文本框(派生)的实例并将其存储在 Winforms 控件类型的变量中。当然,'control' 可以在 OK 周围移动对象,并且您可以处理关于文本框的所有 'controll-y' 事情(例如,top、left、.text 属性)。如果不强制转换指向内存中文本框的“控件”类型变量,则无法看到文本框特定的内容(例如,.multiline),但它仍然存在于内存中。
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) mustexist. 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.
现在想象一下,您有一个控件,并且想要将文本框类型的变量设置为大小写。内存中的控件缺少“多行”和其他文本框内容。如果您尝试引用它们,控件将不会神奇地增长多行属性!该属性(在此处将其视为成员变量,它实际上存储了一个值 - 因为在文本框实例的内存中存在)必须存在。由于您正在投射,请记住,它必须与您指向的对象相同。因此,这不是语言限制,在哲学上不可能以这种方式进行区分。
回答by cjk
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.
你不能把汽车扔到法拉利上——它可能是本田,或者更具体地说,你不能把法拉利 360 Modena 扔到法拉利 360 Challange Stradale——有不同的零件,即使它们都是法拉利 360。
回答by Mehdi LAMRANI
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)
在某些情况下,这样的演员阵容是有意义的。
我的情况是,我正在通过网络接收 BASE 类,我需要更多功能。所以派生它来处理我想要的所有花里胡哨的事情,并将收到的 BASE 类转换为 DERIVED 类根本不是一种选择(抛出 InvalidCastException of Course)
One practical think-out-of-the-boxSOLUTION was to declare an EXTENSION Helper class that was NOT inheriting BASE class actually, but INCLUDING IT as a member.
一个实用的、开箱即用的解决方案是声明一个 EXTENSION Helper 类,该类实际上并未继承 BASE 类,而是将其作为成员包含在内。
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 REALLYhaving an absolute need of derivation, that could be a quick and simple workaround.
如果你有松耦合的,只是需要一些额外的功能,以基础课,而不会真的有推导的绝对需要,这可能是一个快速和简单的解决方法。
回答by parliament
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 AutoMapperto configure a projection.
那将违反面向对象的原则。我想在这里和项目中的其他地方说一个优雅的解决方案是使用像AutoMapper这样的对象映射框架来配置投影。
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:
当应用程序开始调用时AutoMapperConfiguration.Configure()
,您可以像这样进行项目:
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.
属性按约定映射,因此如果继承类,则属性名称完全相同,并且映射是自动配置的。您可以通过调整配置来添加其他属性。请参阅文档。
回答by sirthomas
A variation on the serialization approach for those using ServiceStack:
使用 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.
ServiceStack 的序列化可能非常快,但很明显,这不是低延迟传输中大量转换的解决方案,也不是高度复杂的类型的解决方案。对于任何使用 ServiceStack 的人来说,这可能是显而易见的,但我想我会在期待评论时澄清。
回答by Joe
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
对象的实例应该使用子类的类型创建,您不能将父类型实例转换为子类型
回答by Malik Khalil
I have seen most of the people saying explicit parent to child castingis 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.
正如我们在 .net 中所知,所有铸件都有两大类。
- 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
案例 1.任何直接或间接父母的孩子
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)
案例 2.持有父对象的父变量(不允许)
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.
案例 3.持有子对象的父变量(总是成功)
注意:由于对象具有多态性,因此父类类型的变量可能包含子类型。
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).
结论:首先阅读完之后,希望它现在变得有意义,就像父子转换是可能的(案例 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/asoperators those will help you to take informed decisions and provide safe casting.
回答问题:
您的答案是在第2 种情况下。您可以看到 OOP 不允许进行此类转换,并且您正试图违反 OOP 的基本规则之一。因此,请始终选择安全路径。
此外,为了避免此类异常情况,.net 建议使用is/as运算符,这些运算符将帮助您做出明智的决定并提供安全的投射。