如何允许类属性在c#中具有多种/灵活类型?

Cau*_*tix 5 c# polymorphism

在C#中,我有三个类:Person,Cat和Dog.

Cat和Dog类都有方法Eat().

我希望Person类有一个属性'Pet'.

我希望能够通过Person之类的Person.Pet.Eat()调用Cat和Dog的Eat方法,但我不能,因为Pet属性需要是Cat或Dog类型.

目前我正在使用Person类中的两个属性:PetDog和PetCat.

现在这没关系,但如果我想要100种不同类型的动物作为宠物,那么我真的不想在Person类中拥有100种不同的Pet属性.

有没有办法使用接口或继承?有没有办法可以将Pet设置为Object类型,但仍然可以访问分配给它的动物类的属性?

Dar*_*rov 12

你可以让宠物从一个共同的基类派生出来:

public abstract class Animal
{
    protected Animal() { }

    public abstract void Eat();
}
Run Code Online (Sandbox Code Playgroud)

然后Cat和Dog派生自这个基类:

public class Cat: Animal
{
    public override void Eat()
    {
        // TODO: Provide an implementation for an eating cat
    }
}

public class Dog: Animal
{
    public override void Eat()
    {
        // TODO: Provide an implementation for an eating dog
    }
}
Run Code Online (Sandbox Code Playgroud)

你的Person类将有一个类型的属性Animal:

public class Person
{
    public Animal Pet { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

当你有一个Person实例时:

var person = new Person 
{
    Pet = new Cat()
};
// This will call the Eat method from the Cat class as the pet is a cat
person.Pet.Eat();
Run Code Online (Sandbox Code Playgroud)

您还可以为Eat基类中的方法提供一些常用实现,以避免在派生类中重写它:

public abstract class Animal
{
    protected Animal() { }

    public virtual void Eat()
    {
        // TODO : Provide some common implementation for an eating animal
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,Animal它仍然是一个抽象类,以防止它直接实例化.

public class Cat: Animal
{
}

public class Dog: Animal
{
    public override void Eat()
    {
        // TODO: Some specific behavior for an eating dog like
        // doing a mess all around his bowl :-)

        base.Eat();
    }
}
Run Code Online (Sandbox Code Playgroud)


Eri*_*ert 11

有没有办法使用接口或继承?

是.

接口:创建IEat或IPet接口或您想要表示的任何概念.使接口具有Eat方法.让Cat和Dog实现此界面.让Pet属性属于那种类型.

继承:创建一个抽象基类Animal或Pet或您想要表示的任何概念.在基类上创建一个抽象方法Eat.让猫和狗继承这个基类.让Pet属性属于那种类型.

这两者有什么区别?

使用接口来模拟"X知道如何做Y"的想法.例如,IDisposable意味着"我知道如何处置我所持有的重要资源".这不是关于对象什么的事实,它是关于对象什么的事实.

使用继承来模拟"X是一种Y"的概念.狗是一种动物.

关于接口的事情是你可以拥有任意数量的接口.但是你只能直接从一个基类继承,所以如果你要使用继承,你必须确保你做对了.继承的问题是人们最终制作像"车辆"这样的基础类,然后他们说"一辆军车是一种车辆"和"一艘船是一种车辆",现在你被卡住了:什么是基础毁灭者的类?它既是船只又是军用车辆,它不能同时存在.非常仔细地选择你的"继承支点".

有没有办法可以将Pet设置为Object类型,但仍然可以访问分配给它的动物类的属性?

是的,在C#4中有,但不要这样做.使用接口或继承.

在C#4中,您可以使用"dynamic"在运行时动态调度到Pet中对象的Eat方法.

你不想这样做的原因是因为如果有人在Pet属性中放入Fruit或Handsaw然后尝试将其变为Eat,这将会崩溃并且可怕地死亡.编译时检查的目的是减少程序的脆弱性.如果您有办法进行更多的编译时检查,请使用它.

  • @Jeff:的确,如果你不知道手锯上的鹰,你就会遇到问题.我的建议是:等待南风. (2认同)