【问题标题】:Unable to cast base class to derived class无法将基类转换为派生类
【发布时间】:2018-02-03 10:40:16
【问题描述】:
我有动物的基类和狗的子类
代码如下:
class Animal
{
public int Legs { get; set; }
public string Name { get; set; }
}
class Dog : Animal
{
public int noOfTail { get; set; }
}
在我的主方法中,当我在下面执行时出现异常:
static void Main(string[] args)
{
Animal a = new Animal();
Dog d = new Dog();
d = (Dog)a;
}
但是当我第一次将派生类转换为父类时,我没有收到任何异常,这就是我感到困惑的原因,有人可以解释其背后的原因吗?
static void Main(string[] args)
{
Animal a = new Animal();
Dog d = new Dog();
a = d;
d = (Dog)a;
}
【问题讨论】:
标签:
c#
casting
polymorphism
【解决方案1】:
Animal 对象不能转换为 Dog 类型。另一方面,Dog 对象可以转换为 Dog 类型,即使您将 Dog 对象存储在 Animal 类型的变量中。
在您的第一个示例中,您尝试将Animal 强制转换为Dog,但失败了,因为对象属于错误的类。在第二个示例中,您分配了a = d,因此现在变量a 的类型为Animal,但其运行时类型为Dog。这就是第二个演员起作用的原因。
注意:这只是您的问题的技术部分,但它也有一个逻辑组件:您的类层次结构允许您实例化Animal 类,它不是叶类。
更好的方法是使Animal 成为接口或抽象类。这样,您将能够仅实例化“实际”动物(Dog 以及您希望从 Animal 派生的任何其他内容),而无法创建 Animal 的实例而不说是哪种它代表的动物。
【解决方案2】:
在案例二中,您有一个 dog 和 animal
的实例
Animal a = new Animal();
Dog d = new Dog();
那么你有reference copy的狗到动物
a = d;
所以 a 是指向 d 而 d 是一个 dog 实例和实例属性,如 noOfTail 仍然存在,但在对象 a 中被隐藏且不可用。
然后你有这条线:
d = (Dog)a;
在最后一行中,您有 d 到 a 的参考副本,因此 d 指向 a 的位置是指向所以一切都好。
但万一你想复制一个Instance of child class Dog 到一个Animal 的实例,这样子类的属性就会丢失。您需要通过 Compiler 确认并告诉他您知道 noOfTail 之类的实例属性将不再可用
你的代码大多是这样的:
Animal a = new Animal();
Dog d = new Dog();
d = (a as Dog);
【解决方案3】:
您不能将基类强制转换为派生类,但您可以做相反的事情:将派生类强制转换为基类。
您的第二次尝试有一个非常简单的原因:a = d; => 您正在将派生类实例分配给基类实例。
OOP 基础称为polymorphism。
static void Main(string[] args)
{
Animal a = new Animal();
Dog d = new Dog();
a = d; // you can do that but you cant do d=a
d = (Dog)a;
}
为了更好地理解它,请尝试深入研究那段代码:
public void polymorphism()
{
// thats wrong and the compiler will throw an exception (at design time) because animal is not a dog
Dog d = new Animal();
// thats correct becasue dog is an animal
Animal a = new Dog();
}
【解决方案4】:
动物不是狗。狗是动物。这就是为什么您不能在第一个示例中将 Animal 转换为 Dog。
在第二个示例中,它可以工作,因为 Animal 已被分配了 Dog 的值。当你分配a = d 时,Animal 变成了 Dog。
【解决方案5】:
Animal a = new Animal();
Dog d = new Dog();
d = (Dog)a;
所以总结到 Animal 和 Dog 类,我们可以声明一个对象要成为动物,它必须具有腿和名称属性以及要成为的对象dog 除了name 和legs 属性之外,它还必须具有nooftails 属性。
让我们通过给每个对象的属性明确的值来简化。
Animal a = new Animal();
a.Name="Monkey";
a.Legs=2;
Dog d = new Dog();
a.Name="Dog";
a.Legs=4;
a.noOfTail=1;
假设以下语句不会引发任何编译器错误。
d = (Dog)a;
这是什么意思? Legs 和 name 是您尝试制作或转换或将猴子对象转换为没有 noOftails 属性的狗的猴子对象,它是 nooftails 属性,它唯一地标识或区分 Base Animal 与派生的 Dog 类违背了继承的基本目的。
因此编译器可以防止你做出这种荒谬的演员表。