繁体   English   中英

从基类返回派生类实例

[英]Returning derived class instance from a base class

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

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;

}

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

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;

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

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

如果你需要显示任何一个动物的内容,那么在两个类上重写ToString方法,只需在动物上调用ToString 如果您需要知道狗或猫的名字,那么将一个Name属性添加到Animal 如果你可能的话,你应该在这里使用多态,这样无论使用什么对象,它都只是一个Animal并且只是涉及由于同一方法的不同实现而发生的不同事情。

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

不,你做错了。

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

public abstract Animal getAnimal();

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

Animal dog = new Dog() ;
dog.getAnimal(); 

混淆吧?

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

if(animal is Dog)

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

这是一个真正的基础设计,因为它违反了开放封闭原则 您希望您的类可以打开以进行扩展,但不能修改。 如果明天你想要添加另一个课程,会发生什么?

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建议的虚拟方法。

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

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

Animal a = new Cat();

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM