6

假设我有以下课程:

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对象,然后传递值,(或者有一个采用 type 的构造函数Animal),但这看起来很混乱。

4

10 回答 10

3

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

Animal animal = new Dog();

if( animal is Dog)
{
    //your code
}
于 2013-04-25T12:47:36.287 回答
3

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

Animal a = new Dog();
if (a is Dog )
{
   Dog d = (Dog)a;
   d.sniffBum();
}
于 2013-04-25T12:49:45.463 回答
2

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

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

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

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

于 2013-04-25T12:49:21.747 回答
2

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

您可能想查看装饰器模式,它允许您向实例添加Dog方法。Animal本质上,Dog两者Animal都有IAnimal接口。该类在构造函数中Dog获取一个Animal实例并保留一个内部引用。的实现只是遵循它引用的Dog实例(这允许将转换为并表现得像被包装的多态性)。还具有特定于 Dog的其他方法。IAnimalAnimalDogIAnimalAnimalDog

于 2013-04-25T12:57:09.523 回答
1

动物永远不可能是狗。

制作您的 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");
   }
}
于 2013-04-25T12:59:50.727 回答
0

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

var row = Fetch from database;
Animal animal;
if (row is a dog) animal = new Dog();
else if (row is a cat) animal = new Cat();
于 2013-04-25T12:49:05.790 回答
0

你可以这样做:

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

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

于 2013-04-25T12:52:34.123 回答
0

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

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

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();
}
于 2013-04-25T12:57:37.793 回答
0

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

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

否则很难从创建的对象Animal到具体Dog对象

于 2013-04-25T12:58:27.880 回答
0

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

所以你可以修改你Dog

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();
        }
于 2013-04-25T13:35:45.383 回答