简体   繁体   English

从基类返回派生类实例

[英]Returning derived class instance from a base class

The title may be unclear, but please look at the pattern below 标题可能不清楚,但请看下面的模式

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; }
    }

}

Is this considered a bad practice to have properties in the base class, return derived types. 这被认为是在基类中具有属性,返回派生类型的不良做法。 Or should I do something like 或者我应该做些什么

public abstract AnimalTypeEnum AnimalType { get; }

EDIT: Based on the comments, I guess I should be more clear on what I am trying to achieve. 编辑:根据评论,我想我应该更清楚我想要实现的目标。 A new instance of the Dog or Cat class would be created by a separate function based on certain criteria and would then return Animal type to the caller. DogCat类的新实例将由基于特定条件的单独函数创建,然后将Animal类型返回给调用者。 The calling method would check the type of the returned instance and use it accordingly. 调用方法将检查返回实例的类型并相应地使用它。

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;

}

If you only want the animal you are deriving from you can do this: 如果你只想要你从中获得的动物可以这样做:

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>
{
}

You call this way: 你这样称呼:

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

The calling method would check the type of the returned instance and use it accordingly. 调用方法将检查返回实例的类型并相应地使用它。

There's your problem. 这是你的问题。 It's code smell to need to do that. 这需要代码气味。 You should be able to treat whatever it is as just an object, rather than treating dogs and cats differently. 你应该能够把它只是一个对象,而不是以不同的方式对待狗和猫。

If you need to display the content of either animal, then override the ToString method on both classes and just call ToString on animal. 如果你需要显示任何一个动物的内容,那么在两个类上重写ToString方法,只需在动物上调用ToString If you need to know the name of the dog or cat then add a Name property to Animal . 如果您需要知道狗或猫的名字,那么将一个Name属性添加到Animal If at all possible you should be using polymorphism here so that whatever is using the object treads it as just an Animal and simply involves different things happening as a result of different implementations of the same method. 如果你可能的话,你应该在这里使用多态,这样无论使用什么对象,它都只是一个Animal并且只是涉及由于同一方法的不同实现而发生的不同事情。

If you really, really do need to know whether the Animal is a Dog or a Cat then you can use the is or as operators; 如果你真的,确实需要知道AnimalDog还是Cat那么你可以使用isas运算符; you don't need to add all of the code that you've shown in the OP. 您不需要添加您在OP中显示的所有代码。

Nah you are doing it wrong. 不,你做错了。

The better thing would be to have a single method. 更好的方法是使用单一方法。

public abstract Animal getAnimal();

Any derived class will then know how to return itself. 任何派生类都将知道如何返回自己。 I hope that makes sense. 我希望这是有道理的。 But then I don't think you would want to return an Animal either. 但是我不认为你会想要归还动物。 Doesn't make sense. 没有意义。

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

confusing right? 混淆吧?

You could have an array of Animals/List, iterate through the collection and check like so: 你可以有一个动物/列表数组,遍历集合并检查如下:

if(animal is Dog)

But still you are checking the type. 但你还在检查类型。 If you want to use a base class have it so that it makes sense and exposes a common method. 如果你想使用一个基类让它有意义并暴露一个常见的方法。

This is a really bas design since it violates the Open-Closed principle . 这是一个真正的基础设计,因为它违反了开放封闭原则 You want your classes to be open for extension but closed to modification. 您希望您的类可以打开以进行扩展,但不能修改。 What will happen if tomorrow you'll want to add another class? 如果明天你想要添加另一个课程,会发生什么?

public class Donkey : Animal
{
}

You will have to go and change the base class so it will have a property GetDonkey . 您将不得不去更改基类,因此它将具有GetDonkey属性。 You will also have to go and change all the classes that use your class and add if (animal.GetDonkey == null) 您还必须更改所有使用您的类的类并添加if (animal.GetDonkey == null)

What you should do is use a factory design pattern like this: 你应该做的是使用这样的工厂设计模式:

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

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

or you should use a virtual method like @Lews Therin suggested. 或者你应该使用@Lews Therin建议的虚拟方法。

It doesn't seem very useful to have properties that just return the object they're called on. 拥有只返回被调用对象的属性似乎没有用。

Maybe you're just looking for a way to downcast from a superclass to a subclass? 也许你只是在寻找一种从超类转向子类的方法? If so, just use casts: 如果是这样,只需使用强制转换:

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