从基类返回派生类实例

时间:2012-10-18 18:38:48

标签: c# inheritance

标题可能不清楚,但请查看下面的模式

public abstract class Animal
{

    public abstract Dog GetDog { get; }

    public abstract Cat GetCat { get; }

}

public class Dog : Animal
{

    public override Dog GetDog {
        get { return this; }
    }

    public override Cat GetCat {
        get { return null; }
    }

}

在基类中包含属性,返回派生类型是不好的做法。或者我应该做点什么

public abstract AnimalTypeEnum AnimalType { get; }

编辑:根据评论,我想我应该更清楚我想要实现的目标。 DogCat类的新实例将由基于特定条件的单独函数创建,然后将Animal类型返回给调用者。调用方法将检查返回实例的类型并相应地使用它。

public Animal CreateAnimal(string path)
{

    //Process the document in path and create either a new instance of dog or cat

    Dog dg = new Dog();

    return dg;

}

5 个答案:

答案 0 :(得分:12)

如果你只想要你从中获得的动物可以这样做:

public abstract class Animal<T> where T: Animal<T>
{
    public T GetAnimal 
    {
        get { return (T)this; }
    }
}

public class Dog : Animal<Dog>
{
}

public class Cat : Animal<Cat>
{
}

public class Giraffe : Animal<Giraffe>
{
}

你这样称呼:

var cat = new Cat();
var dog = new Dog();
var giraffe = new Giraffe();
Cat cat2 = cat.GetAnimal;
Dog dog2 = dog.GetAnimal;
Giraffe giraffe2 = giraffe.GetAnimal;

答案 1 :(得分:6)

  

调用方法将检查返回实例的类型并相应地使用它。

有你的问题。这需要代码气味。你应该能够把它只是一个对象,而不是以不同的方式对待狗和猫。

如果您需要显示任一动物的内容,请覆盖两个类的ToString方法,然后在动物上调用ToString。如果您需要知道狗或猫的名字,请将Name属性添加到Animal。如果可能的话,你应该在这里使用多态,这样任何使用该对象的东西都只是Animal,并且由于同一方法的不同实现而简单地涉及不同的事情。

如果您确实需要知道AnimalDog还是Cat,那么您可以使用isas运营商;您不需要添加您在OP中显示的所有代码。

答案 2 :(得分:5)

不,你做错了。

更好的方法是使用单一方法。

public abstract Animal getAnimal();

任何派生类都将知道如何返回自己。我希望这是有道理的。但是我不认为你会想要归还动物。没有意义。

Animal dog = new Dog() ;
dog.getAnimal(); 
困惑吧?

你可以有一个动物/列表数组,遍历集合并检查如下:

if(animal is Dog)

但是你还在检查类型。如果你想使用一个基类,那么它就有意义并暴露一个常用的方法。

答案 3 :(得分:1)

这是一个非常简洁的设计,因为它违反了Open-Closed principle。您希望您的类可以打开以进行扩展,但不能修改。 如果明天你想要添加另一个课程会怎么样?

public class Donkey : Animal
{
}

您必须更改基类,以便它具有属性GetDonkey。 您还必须更改使用您的课程的所有课程并添加if (animal.GetDonkey == null)

你应该做的是使用这样的工厂设计模式:

public static class AnimalFactory
{
  public static Dog GetDog()
  {
    return new Dog();
  }

  public static Cat GetCat()
  {
    return new Cat();
  }
}

或者你应该使用像@Lews Therin建议的虚拟方法。

答案 4 :(得分:-2)

拥有只返回被调用对象的属性似乎没什么用处。

也许你只是在寻找一种从超类向子类转发的方法?如果是这样,只需使用强制转换:

Animal a = new Cat();

try
{
    Dog d = (Dog)a;
}
catch (InvalidCastException)
{
    try
    {
        Cat c = (Cat)a;
    }
    catch (InvalidCastException)
    {
    }
}