[英]Passing Constrained Generic Type to Non-Generic Method
為什么我不能傳遞此類的實例...
class Item<T> where T : Thing { }
...變成這種方法:
void DoSomething(Item<Thing> item);
由於我已將Item<T>
約束為Item<Thing>
,因此在將我的項目發送到DoSomething
之前應該可以安全地進行轉換-但是為什么框架不處理此問題呢?
假設您有一堂課:
public class SomeOtherThing : Thing { }
無法將Item<SomeOtherThing>
轉換為Item<Thing>
。 她們不一樣。
讓我們暫時假設項目看起來像這樣:
public class Item<T>
{
public T Value { get; set; }
}
然后, DoSomething
可能會執行以下操作:
void DoSomething(Item<Thing> item)
{
item.Value = new Thing();
}
如果將Item<SomeOtherThing>
傳遞給DoSomething
您現在剛剛將一個新的Thing
分配給Value
, 但是value是SomeOtherThing
類型的屬性,則無法為其設置Thing
對象 。 這樣會破壞類型系統。 編譯器知道這是一個選擇。 因此(以及具有相同基本問題的許多其他操作),不能將Item<SomeOtherThing>
轉換為Item<Thing>
。
所以,你可以做什么?
好吧,如果您控制DoSomething
的定義,也許它也應該是通用的。
如果DoSomething
看起來像這樣:
void DoSomething<T>(Item<T> item)
where T : Thing
{ }
然后,您可以使用Item<SomeOtherThing>
進行調用,因為以前可能導致問題的操作在DoSomething
不再有效。
想像
class Derived : Thing {}
無法將Item<Derived>
分配給Item<Thing>
。
您需要像這樣在方法聲明中更具體一些;
void DoSomething<T>(Item<T> item)
where T : Thing
{
// now your method knows that T must be of time Thing and you can use it
}
您遇到的問題是您的方法特定於Item<Thing>
,而Item<Something>
不是有效的參數。 C#不支持通用類協方差。 您有幾種選擇。
“最簡單”的事情就是簡單地使您的方法通用,並為Thing添加約束。 這將是第一個建議的方法。
void DoSomething<T>(Item<T> item) where T : Thing
{
}
這將授予您訪問Thing
所有成員(如果適用)的權限,同時仍然擁有可以滿足所有子類的方法。
另一個有更多限制的選項是讓Item<Thing>
的非通用基礎就是Item
。 (在其中,無論您以前暴露T的哪個位置,都將暴露object
。請考慮: IEnumerable<T>
: IEnumerable
。)
void DoSomething(Item item)
{
}
您的方法只需要Item
,就可以使用它。 但是,如果您有使用Thing
的特定要求,那么它會更加微妙,您需要進行適當的轉換,但同時也面臨着有人傳遞的實例不是 Item<T>
的可能性,其中T是一個東西。
另一種選擇是不保留方法的簽名,並將其從類轉換為接口,從而允許您使用協方差。 (.NET 4.0在接口和委托類型中支持Co / contravariance。)
interface Item<out T>
{
T Get();
// void Set(T foo); // invalid
}
同樣,這里的問題是:1)(顯然)您需要更改類型,但是2)您將只能在輸出位置暴露T
注意,支持Get()
方法。 Set(T)
方法不是,因為T
是輸入,這使得該接口不是協變有效的。 (想象一下傳入一個Item<Something>
,並且您的方法嘗試使用SomeOtherThing
調用Set
。兩者都是Things
,但是顯然第二個不適用於第一個。)因此,如果您需要同時支持T
作為輸出和輸入,則無法利用這種方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.