【问题标题】:How do I turn an Animal instance into a Dog instance?如何将 Animal 实例变成 Dog 实例?
【发布时间】:2013-04-25 12:45:18
【问题描述】:

假设我有以下课程:

class Animal
{
    public long Id { get; set; }
    public string Name { get; set; }
}

class Dog:Animal
{
    public void sniffBum()
    {
        Console.WriteLine("sniff sniff sniff");
    }
}

如果我有一个Animal 的实例,如何将其转换为Dog? 像这样的:

Animal a = new Animal();
if ( some logic to determine that this animal is a dog )
{
    Dog d = (Dog)a;
    d.sniffBum();
}

基本上我不能使用接口。我将永远有一个Animal 对象从我的数据库中出来。 Dog 没有比Animal 更多的参数,只有新方法。

我可以创建一个新的Dog 对象,然后传递值,(或者有一个采用Animal 类型的构造函数),但这看起来很混乱。

【问题讨论】:

  • 如果所有对象都来自 Animal 类型,您还需要以某种方式将类型保存在数据库中
  • 拥有一个采用Animal 类型参数的构造函数一点也不混乱 IMO
  • 你的Animalclass 可以修改吗?

标签: c# oop inheritance


【解决方案1】:

首先将动物创建为狗,然后检查它是否is

Animal a = new Dog();
if (a is Dog )
{
   Dog d = (Dog)a;
   d.sniffBum();
}

【讨论】:

    【解决方案2】:

    要检查对象是否可以转换为类型,请使用 is 关键字。

    Animal animal = new Dog();
    
    if( animal is Dog)
    {
        //your code
    }
    

    【讨论】:

    • 参见msdn docs about is operator msdn.microsoft.com/en-us/library/scekt9xw(v=vs.71).aspx is 运算符用于检查对象的运行时类型是否与给定类型兼容。
    • 没有投反对票,但我很确定这是关于创建一个动物对象然后检查它是否是狗,永远不会工作
    • -1,正如@Jeroen 正确指出的那样,OP 的问题是关于其他问题的。
    • 我认为这里的重点是使用 is 运算符,要更正答案,您可以添加 var animal = new Dog();结案。
    • 问题指出 Animal 来自数据库,然后他们想将其转换为 Dog - 这意味着 is 运算符将始终返回 false,因为实例是作为 Animal 创建的,而不是作为狗。
    【解决方案3】:

    如果 Animal 实例从未是 Dog 实例,则强制转换检查将不起作用。

    您可能想查看Decorator Pattern,它允许您将Dog 方法添加到Animal 实例。本质上,DogAnimal 都具有IAnimal 接口。 Dog 类在构造函数中采用 Animal 实例并保留内部引用。 DogIAnimal 实现简单地遵循它引用的 Animal 实例(它允许将 Dog 强制转换为 IAnimal 并表现得像包装的 Animal 以实现多态性)。 Dog 还具有特定于 Dog 的其他方法。

    【讨论】:

      【解决方案4】:

      您可以使用is 来做到这一点,但由于您想要对任何您发现的狗进行呼叫,因此使用as 会更好:

      var dog = a as Dog;
      if (dog != null)
      {
          dog.sniffButt();
      }
      

      但是您应该知道,这种安排(尝试确定值的运行时类型以便您可以将其转换为方便的东西)通常是有充分理由不赞成的。你可以很容易地过度检查并最终检查狗、猫、鹦鹉、鱼、乌龟……我相信你可以想象出结果的混乱。

      如果您的需求指向该场景,更好的解决方案是使用访问者设计模式。

      【讨论】:

        【解决方案5】:

        动物永远不可能是狗。

        制作你的 Dog 构造函数,以 Animal 作为参数。

        class Dog : Animal
        {
           public Dog(Animal a)
           {
              this.Name = a.Name;
              this.Id = a.Id;
           }
        
           public void sniffBum()
           {
               Console.WriteLine("sniff sniff sniff");
           }
        }
        

        【讨论】:

          【解决方案6】:

          我不是这样工作的。强制转换是一种将实例解释为给定类型的操作,它不会改变它的类型。在您的情况下,您必须首先确定该特定数据库行中有哪种动物,然后实例化正确的祖先。伪代码:

          var row = Fetch from database;
          Animal animal;
          if (row is a dog) animal = new Dog();
          else if (row is a cat) animal = new Cat();
          

          【讨论】:

            【解决方案7】:

            你可以这样做:

            var dog = a as Dog;
            if(dog != null)
            {
                dog.DoSomething();
            }
            

            如果你需要在后面转换它,最好检查 a 是否是 Dog。请参阅以下答案: Casting vs using the 'as' keyword in the CLR

            【讨论】:

              【解决方案8】:

              我会在Dog 对象或某种DogFactory 上创建一些静态方法,您可以将Animal 作为参数传递并让它创建您的Dog,或返回null

              在这种方法中,您可以检查您的动物特征,看看您是否希望它成为一只狗(4 条腿、比特等)

              否则很难从创建为Animal 的对象转换为具体的Dog 对象

              【讨论】:

                【解决方案9】:

                你不能把动物变成狗,它可能是一只猫!我认为你想要实现的是从另一个从 db 获取的Animal 类型的对象创建一个Dog 类型的对象。

                一种方法是在Dog 的重载构造函数中接受Animal 类型的对象:

                class Dog:Animal
                {
                    public Dog(Animal animal)
                    {
                        this.Id = animal.Id;
                       this.Name = animal.Name;
                    }
                ...
                }
                

                这样,您可以简单地使用以下内容:

                if ( some logic to determine that this animal is a dog )
                {
                    Dog d = new Dog(a);
                    d.sniffBum();
                }
                

                【讨论】:

                  【解决方案10】:

                  Kamyar 是对的,因为就像你自己告诉我们的那样,没有办法做到这一点

                  i will always have an Animal object coming out of my database like that
                  

                  所以你需要将类型也保存在你的数据库中

                  之后,您应该将您的 Animal 更改为

                  public class Animal
                  {
                      public long Id { get; set; }
                      public string Name { get; set; }
                      public string AnimalType { get; private set; }
                  
                      public Animal() { }
                      public Animal(string type)
                      {
                          AnimalType = type;
                      }
                  
                      // to denie self repeading if all animales have the same Properties
                      protected void set(Animal a)
                      {
                          Id = a.Id;
                          Name = a.Name;
                          AnimalType = a.AnimalType;
                      }
                  }
                  

                  .

                  Dog doesnt have any more parameters than Animal has, only new methods
                  

                  所以你可以修改你的Dogto

                  public class Dog : Animal
                  {
                      public Dog(Animal a) 
                      {
                          base.set(a);
                      }
                  
                      public void sniffBum()
                      {
                          Console.WriteLine("sniff sniff sniff");
                      }
                  }
                  

                  .

                  i could just create a new Dog object, and pass the values accross, (...), but this just seems messy
                  

                  我认为没有办法,而且看起来也不那么混乱

                  这里是如何使用的例子

                          Animal a = new Animal("Dog");
                          if (a.AnimalType =="Dog")
                          {
                              Dog d = new Dog( a);
                              d.sniffBum();
                          }
                  

                  【讨论】:

                    猜你喜欢
                    • 2014-04-24
                    • 1970-01-01
                    • 2015-04-26
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-09-21
                    • 2014-10-05
                    相关资源
                    最近更新 更多