簡體   English   中英

如何允許類屬性在c#中具有多種/靈活類型?

[英]How to allow Class Property be of multiple/flexible types in c#?

在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類型,但仍然可以訪問分配給它的動物類的屬性?

你可以讓寵物從一個共同的基類派生出來:

public abstract class Animal
{
    protected Animal() { }

    public abstract void Eat();
}

然后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
    }
}

並且您的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或您想要表示的任何概念。 在基類上創建一個抽象方法Eat。 讓貓和狗繼承這個基類。 讓Pet屬性屬於那種類型。

這兩者有什么區別?

使用接口來模擬“X知道如何做Y”的想法。 例如,IDisposable意味着“我知道如何處置我所持有的重要資源”。 這不是關於對象什么的事實,它是關於對象什么的事實。

使用繼承來模擬“X是一種Y”的概念。 狗是一種動物。

關於接口的事情是你可以擁有任意數量的接口。 但是你只能直接從一個基類繼承,所以如果你要使用繼承,你必須確保你做對了。 繼承的問題是人們最終制作像“車輛”這樣的基礎類,然后他們說“一輛軍車是一種車輛”和“一艘船是一種車輛”,現在你被卡住了:什么是基礎毀滅者的類? 它既是船只又是軍用車輛, 它不能同時存在 非常仔細地選擇“繼承支點”

有沒有辦法可以將Pet設置為Object類型,但仍然可以訪問分配給它的動物類的屬性?

是的,在C#4中有,但不要這樣做 使用接口或繼承。

在C#4中,您可以使用“dynamic”在運行時動態調度到Pet中對象的Eat方法。

你不想這樣做的原因是因為如果有人在Pet屬性中放入Fruit或Handsaw然后嘗試將其變為Eat, 這將會崩潰並且可怕地死亡 編譯時檢查的目的是減少程序的脆弱性。 如果您有辦法進行更多的編譯時檢查,請使用它。

使用界面;

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM