[英]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.