簡體   English   中英

具有強類型返回類型的抽象方法

[英]Abstract method with strongly typed return type

考慮以下類:

public abstract class Animal
{
    public abstract Animal GiveBirth();
}

public class Monkey : Animal
{
    public override Animal GiveBirth()
    {
        return new Monkey();
    }
}

public class Snake : Animal
{
    public override Animal GiveBirth()
    {
        return new Snake();
    }
}

//That one doesnt makes sense.
public class WeirdHuman: Animal
{
    public override Animal GiveBirth()
    {
        return new Monkey();
    }
}

我正在尋找一種強制覆蓋GiveBirth方法的返回類型的方法,以便它總是返回實際的類類型,這樣沒有WeirdHuman可以生成一個Monkey

我覺得答案是關於泛型類型的,但我看不出我能做到這一點。

預期結果的例子:

public abstract class Animal
{
    public abstract /*here a way to specify concrete type*/ GiveBirth();
}

public class Monkey : Animal
{
    public override Monkey GiveBirth() //Must returns an actual Monkey
    {
        return new Monkey();
    }
}

如果清楚地解釋,“絕對不可能” 可能是一個答案。

這是共變量返回,C#不支持。 我每天都感嘆。 你可以做的最好的辦法就是使用泛型返回類型並在泛型類型上指定where條件,但是這也可能導致你在遇到通用參數要求的情況下遇到其他問題。

public abstract class Animal<TBirthType> where TBirthType : Animal<TBirthType>
{
    public abstract TBirthType GiveBirth();
}

public class Monkey<TBirthType> : Animal<TBirthType> where TBirthType : Monkey<TBirthType>
{
    public override TBirthType GiveBirth()
    {
        return new Monkey<Monkey>();
    }
}

或者,如果您不需要任何進一步的繼承,則可以關閉通用。

public class Monkey : Animal<Monkey>
{
    public override Monkey GiveBirth()
    {
        return new Monkey();
    }
}

請注意,僅協方差仍然不足以確保不會形成行為不當的派生類型,但它將允許將返回類型指定為正在使用的類型。 但是仍然沒有辦法將它從抽象類中鎖定下來。 您可以通過從基礎級別實現的方法的反射來管理運行時檢查,該方法將在運行時檢查類型,但這也可能非常混亂。

據我所知,沒有一種干凈的方法可以純粹在單個類層次結構中支持它。 使用重復的泛型類型參數,例如

public class Animal<T> where T : Animal<T> { }

如果你控制整個層次結構可能是可以接受的,因此可以排除像這樣的類

public class WierdHuman<Monkey> { }

你真正想要的是像Haskell的類型類,你可以在這里抽象出類本身的具體類型。 您可以在C#中獲得的最接近的是定義一個實現所需功能的代理對象,然后將其傳遞到您需要的任何位置。

在您的情況下,這意味着創建一個生育界面,並為每個具體的動物類型實施它。

您需要此功能的方法需要“類型類實例”的額外參數。 這些方法可以限制通用動物類型相同:

public interface ISpawn<T> where T : Animal
{
    public T GiveBirth();
}

public void Populate<T>(T parent, ISpawn<T> spawn) where T : Animal
{
}

你可以做這樣的事情,它迫使Animal<T>的實現者實現一個Animal<T> GiveBirth()方法,該方法返回與type參數相同的類型,它本身被約束為一種動物。

這不是你想要的,但你可以看到:

public abstract class Animal<T> where T: Animal<T>
{
    public abstract Animal<T> GiveBirth();
}

public class Monkey: Animal<Monkey>
{
    public override Animal<Monkey> GiveBirth()
    {
        return new Monkey();
    }
}

public class Snake: Animal<Snake>
{
    public override Animal<Snake> GiveBirth()
    {
        return new Snake();
    }
}

public class WeirdHuman: Animal<WeirdHuman>
{
    public override Animal<WeirdHuman> GiveBirth()
    {
        return new Monkey(); // Won't compile of course.
    }
}

如果您注釋掉public override Animal<Monkey> GiveBirth()方法,您將看到編譯器抱怨並說出如下內容:

錯誤1'ConsoleApplication1.Monkey'未實現繼承的抽象成員'ConsoleApplication1.Animal.GiveBirth()'

不幸的是,您必須使用SomeKindOfAnimal: Animal<SomeKindOfAnimal>語法聲明類,但這可能對您SomeKindOfAnimal: Animal<SomeKindOfAnimal>

另見本帖。

唉,這不太有效,因為它允許你這樣做:

public class Monkey: Animal<WeirdHuman>
{
    public override Animal<WeirdHuman> GiveBirth()
    {
        return new WeirdHuman();
    }
}

換句話說,它將類型參數約束為一種動物,並且它還將GiveBirth()的返回類型約束為與類型參數相同; 但就是這樣。 在某些情況下,這已足夠,但可能不適合您的目的。

不過,也許這種方法值得了解。

暫無
暫無

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

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