2010-09-07 26 views
5

在C#中,我有三个类:Person,Cat和Dog。如何让类属性是多个/灵活类型在C#中?

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

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

我希望能够通过像Person.Pet.Eat()这样的东西来调用Cat和Dog的Eat方法,但我不能,因为Pet属性需要是Cat类型或狗。

目前我在Person类中使用了两个属性:PetDog和PetCat。

现在可以,但如果我想要100种不同类型的动物作为宠物,那么我并不想在Person类中拥有100种不同的宠物属性。

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

+7

这是功课吗? – 2010-09-07 17:10:19

+2

闻起来像给我做功课。家庭作业问题没有任何问题,但他们应该被标记为这样。如果家庭作业相关,请在问题中添加“作业”标签。 – 2010-09-07 17:12:18

+2

我不喜欢这个Person.Pet.Eat(),读错误的方式,我可能会害怕这个人会对宠物做什么..如何Person.FeedPet()代替。对于动物来说.. – 2010-09-07 17:14:52

回答

12

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

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

当你拥有了人的一个实例:

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方法的共同实现,以避免在派生类中重写它ES:

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(); 
    } 
} 
+0

它如何知道在调用'person.Pet.Eat()'时吃哪个类的函数? – 2010-09-07 17:20:24

+0

取决于'Pet'属性的实际类型。 – 2010-09-07 17:21:09

+0

@Abe Miessler:它不在编译时。这个决定是在运行时做出的,当它知道什么类型的实例实际存储在'person.Pet'中。 – Timwi 2010-09-07 17:22:06

1

使用接口;

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(); 

执行正确的空支票,当您去。

+2

制作''Pet' ICanEat'将使演员不必要。此外,你应该*永远不会*使用'as'操作符来保证成功的投射操作,明确的投射就是你所需要的。由于失败的可能性,在解除引用前应该跟随一个空测试。 – Ani 2010-09-07 17:15:23

1

使用抽象类。

public abstract class Pet { public abstract void Eat(); } 

public class Dog : Pet { } 
public class Cat : Pet { } 

public class Person { 
    public Pet Pet; 
} 

我相信你可以做剩下的事情。

0

为什么不创建一个基类的宠物

public abstract class Pet{ 

    public abstract void Eat(); 

} 
0

有这种猫与狗从一个接口继承IPet

public interface IPet 
{ 
    bool hungry(); 
    void Eat(); 
} 
11

是否有办法解决这使用接口或继承?

是。

接口:使接口IEat或IPet或任何您想要表示的概念。使界面有一个Eat方法。有猫和狗实现这个接口。让Pet属性成为这种类型。

继承:创建一个抽象基类动物或宠物或任何想要表示的概念。做一个抽象方法吃基础类。猫和狗从这个基类继承。让Pet属性成为这种类型。

这两者有什么区别?

使用接口来模拟“X知道如何做Y”的想法。例如,一次性使用“一次性”意味着“我知道如何处理我所持有的重要资源”。这不是关于什么对象的事实,关于什么对象确实是

使用继承来模拟“X是一种Y”的想法。狗是一种动物。

接口的事情是你可以拥有尽可能多的接口。但是你只能从直接继承一个基类,所以如果你打算使用继承,你必须确保你做对了。继承问题是人们最终制造出类似“车辆”的基础类,然后他们说“军车是一种车辆”,“船舶是一种车辆”,现在你被困住了:基础是什么驱逐舰的类?它既是船舶又是军用车辆,它不能同时为非常仔细地选择你的“继承枢轴”

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

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

在C#4中,您可以使用“动态”在运行时动态分派到Pet上的对象的Eat方法。

你不想做,这是因为这将崩溃和死亡可怕的应该有人把水果或手锯在宠物属性,然后试着让它吃的原因。编译时检查的重点是降低程序的脆弱性。如果您有办法进行更多编译时检查,请使用它。

+0

如果我有一把手锯作为宠物,我可能疯了,觉得它吃了。 – 2010-09-07 17:23:40

+2

@Jeff:的确,如果你不了解手锯的鹰派,你就会遇到问题。我的建议:等待南风。 – 2010-09-07 17:26:03

+0

谢谢,这非常有帮助,也很机智。一旦我得到足够的代表,我会投票。 – Caustix 2010-09-07 17:31:35