簡體   English   中英

C#泛型類型約束

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

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