[英]C# generics type constraint
這不應該是有效的C#代碼嗎?
class A<T> where T : class {
public void DoWork<K>() where K : T {
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class {
}
編譯器吐出此錯誤:
錯誤CS0452:類型“K”必須是引用類型,以便在泛型類型或方法“ConsoleApplication1.B”中將其用作參數“U”
編譯器是否應該能夠確定K是約束為T類型還是從T派生,因此它顯然應該是引用類型(T被約束為引用類型)?
我之前的回答不正確; 我刪除了它。 感謝用戶配置器指出我的錯誤。
編譯器是否應該能夠確定K是約束為T類型還是從T派生,因此它顯然應該是引用類型(T被約束為引用類型)?
沒有。
K被約束為T型或從T派生的類型.T被約束為參考類型。 這並不意味着K是參考類型。 Viz:object是引用類型,int是從object派生的類型。 如果T是對象,則K可以是int,這不是引用類型。
指定type參數時將應用約束。 雖然為U指定了K,但尚未為K指定類型。由於U要求其類型為引用類型,因此編譯器希望確認K確實是引用類型,但它不能。 因此,您需要明確說明它將是。
規范在4.4.4節中說明:
對於每個where子句,將針對每個約束檢查與命名的類型參數對應的類型參數A.
然后:
如果給定類型參數不滿足一個或多個類型參數的約束,則會發生編譯時錯誤。
由於不繼承類型參數,因此也不會繼承約束。
最后一點表明K不會繼承T的約束。
更新
雖然我的結論看起來是正確的,但我的證據有點不穩定,正如Eric Lippert回應中現在刪除的回復中所闡明的那樣。 在那里,Eric表示規范的正確部分是:
如果類型參數具有引用類型約束或其有效基類不是對象或
System.ValueType
則已知類型參數是引用類型。
約束不以這種方式級聯。 每個通用簽名都有自己獨特的約束,這些約束獨立於可能隱含的任何子約束進行評估。 你需要在K以及T和U上進行類聲明,即使它已經暗示了T.
嘗試這個:
class A<T> where T : class
{
public void DoWork<K>() where K : class, T
{
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class
{
}
不幸的是,看起來編譯器不夠亮,不足以推斷。 但是,如果你為K添加更多約束,你應該好好去。
我想你需要指定K:class和T.
class A<T> where T : class {
public void DoWork<K>() where K : class, T {
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class {
}
你應該做這個 :
class A<T> where T : class
{
public void DoWork<K>() where K: class, T
{
var b = new B<K>(); // <- compile time error
}
}
class B<U> where U : class
{
}
編輯:如果您沒有將K指定為類並且具有無參數構造函數,那么您將編譯時錯誤:類型U必須是ref類型,並且需要具有無參數構造函數
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.