【问题标题】: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】:

    在案例二中,您有一个 doganimal

    的实例
    Animal a = new Animal();
    Dog d = new Dog();
    

    那么你有reference copy动物

    a = d;
    

    所以 a 是指向 dd 是一个 dog 实例和实例属性,如 noOfTail 仍然存在,但在对象 a 中被隐藏且不可用。 然后你有这条线:

    d = (Dog)a;
    

    在最后一行中,您有 da 的参考副本,因此 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;
          

          所以总结到 AnimalDog 类,我们可以声明一个对象要成为动物,它必须具有腿和名称属性以及要成为的对象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 类违背了继承的基本目的。

          因此编译器可以防止你做出这种荒谬的演员表。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-12-06
            • 2017-01-08
            • 2013-11-17
            • 2013-04-29
            • 2019-04-17
            • 2021-02-18
            相关资源
            最近更新 更多