如何在c#中允许类属性具有多种/灵活的类型?
在C#中,我有三类:人、猫和狗 Cat和Dog类都有Eat()方法 我希望Person类有一个属性“Pet” 我希望能够通过Person调用Cat和Dog的Eat方法,比如Person.Pet.Eat(),但是我不能,因为Pet属性需要是Cat或Dog类型 目前,我在Person类中使用了两个属性:PetDog和PetCat 现在这还可以,但是如果我想要100种不同类型的动物作为宠物,那么我真的不想在Person类中有100种不同的宠物属性 有没有办法使用接口或继承来解决这个问题?是否有一种方法可以将宠物设置为Object类型,但仍然可以访问分配给它的任何动物类别的属性?使用接口如何在c#中允许类属性具有多种/灵活的类型?,c#,polymorphism,C#,Polymorphism,在C#中,我有三类:人、猫和狗 Cat和Dog类都有Eat()方法 我希望Person类有一个属性“Pet” 我希望能够通过Person调用Cat和Dog的Eat方法,比如Person.Pet.Eat(),但是我不能,因为Pet属性需要是Cat或Dog类型 目前,我在Person类中使用了两个属性:PetDog和PetCat 现在这还可以,但是如果我想要100种不同类型的动物作为宠物,那么我真的不想在Person类中有100种不同的宠物属性 有没有办法使用接口或继承来解决这个问题?是否有一种方法
abstract class Animal
{
public virtual void DoSomething() { }
}
interface ICanEat
{
void Eat();
}
class Dog : Animal, ICanEat
{
public void Eat()
{
Console.Out.WriteLine("Dog eat");
}
}
class Cat : Animal, ICanEat
{
public void Eat()
{
Console.Out.WriteLine("Cat eat");
}
}
class Person
{
public Animal MyAnimal { get; set; }
}
然后你可以打电话
(person.MyAnimal as ICanEat).Eat();
执行正确的空检查。使用抽象类
public abstract class Pet { public abstract void Eat(); }
public class Dog : Pet { }
public class Cat : Pet { }
public class Person {
public Pet Pet;
}
我相信您可以完成其余的工作。为什么不创建一个Pet类型的基类呢
public abstract class Pet{
public abstract void Eat();
}
让这只猫和狗从接口继承
IPet
public interface IPet
{
bool hungry();
void Eat();
}
您可以让宠物派生自一个公共基类:
public abstract class Animal
{
protected Animal() { }
public abstract void Eat();
}
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
}
}
然后让Cat和Dog从这个基类派生:
public abstract class Animal
{
protected Animal() { }
public abstract void Eat();
}
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
}
}
Person类的属性类型为Animal
:
public class Person
{
public Animal Pet { get; set; }
}
当您有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();
您还可以在基类中为
Eat
方法提供一些通用实现,以避免在派生类中重写它:
public abstract class Animal
{
protected Animal() { }
public virtual void Eat()
{
// TODO : Provide some common implementation for an eating animal
}
}
请注意,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();
}
}
有没有办法使用接口或继承来解决这个问题
对
接口:制作一个IEat或IPet接口或任何你想表达的概念。使接口具有Eat方法。让Cat和Dog实现此接口。让Pet属性为该类型
继承:制作一个抽象的基类Animal或Pet或任何您想要表示的概念。在基类上创建一个抽象方法。让Cat和Dog从此基类继承。让Pet属性为该类型
这两者有什么区别
使用接口来模拟“X知道如何做Y”的想法。例如,IDisposable的意思是“我知道如何处置我持有的重要资源”。这不是关于对象是什么的事实,而是关于对象做什么的事实
使用继承来模拟“X是Y的一种”的想法。狗是一种动物
关于接口的问题是,您可以拥有任意数量的接口。但是您只能直接从一个基类继承,所以如果要使用继承,您必须确保正确地继承。继承的问题是,人们最终制造了“车辆”这样的基类,然后他们说“军用车辆是一种车辆”和“舰船是一种车辆”,现在你陷入了困境:驱逐舰的基类是什么?它既是一艘船又是一辆军用车辆,不可能两者兼而有之非常小心地选择“继承轴心”
是否有一种方法可以将宠物设置为Object类型,但仍然可以访问分配给它的任何动物类的属性
是的,在C#4中有,但不要这样做。使用接口或继承
在C#4中,您可以使用“dynamic”在运行时获得对Pet中对象的Eat方法的动态分派
你不想这样做的原因是,如果有人把水果或手锯放在宠物的财产里,然后试图让它吃,它会崩溃并可怕地死去。编译时检查的目的是减少程序的脆弱性。如果你有办法进行更多的编译时检查,那就用它。这是作业吗?我觉得很像作业。家庭作业问题没有什么问题,但它们应该被标记为这样。如果是与家庭作业相关的问题,请在问题中添加“家庭作业”标签。我不喜欢这个人。Pet.Eat(),请以错误的方式阅读。我可能担心这个人会对宠物做什么。。那么Person.FeedPet()呢。看在动物的份上……哈哈,这不是家庭作业——我只是用那种方式写的,这样每个人都能理解这个问题。如果我把它们放在这里,我使用的类和属性的实际名称会读起来像中文。也许我应该从事教学工作?;)@原因:不用担心,这可能是关于多态性的教科书作业:)使
Pet
类型为icant
的属性变得不必要。此外,对于保证成功的强制转换操作,决不能使用as
运算符,您需要的是显式强制转换<代码>as在取消引用之前应该跟一个空测试,因为可能有失败的强制转换。当您调用person.Pet.Eat()
时,它如何知道要运行哪个类的Eat函数?这取决于Pet
属性的实际类型。@Abe Miessler:编译时它不知道。当它知道person.Pet中实际存储的实例类型时,就会在运行时做出决定。因此,通过将抽象类作为person类的成员,您可以将任何派生类分配给该成员?IEPerson.Pet=新猫()
或Person.Pet=新狗()代码>?@Abe Miessler,是的,你可以将它分配给任何派生类。如果我养了一把手锯作为宠物,我可能会疯狂到认为它会吃东西。@Jeff:事实上,如果你不知道鹰和手锯的区别,你就有问题了。我的建议是:等待南风。谢谢,这很有帮助,也很机智。一旦我得到足够的支持,我会投票支持的。