2012-01-17 97 views
8

考慮下面的類:類和方法層面的泛型類型約束作用

public class DerivedClassPool<TBase> where TBase : class 
{ 
    public TBase Get(Type componentType) 
    { 
     // Not important, but you get the idea 
     return Activator.CreateInstance(componentType) as TBase; 
    } 

    public TDerived SomeMethod<TDerived>() where TDerived : TBase 
    { 
     return Get(typeof(TBase)) as TDerived; 
    } 
} 

注意我已經限制了TBase泛型類的說法應是一個類:where TBase : class
我也制約了TDerived通用方法的參數是TBase或從中衍生出來的東西:where TDerived : TBase

我上as TDerived行錯誤:

類型參數「TDerived」不能使用的「爲」經營者,因爲它沒有一個類類型約束,也不是一個「類」約束

我明白,爲了防止我需要添加約束class的錯誤,所以我會得到:

where TDerived : class, TBase 

爲什麼我必須這樣做,當TBase已被限制爲一個類和TDerived被約束爲TBase或從它派生?

+1

請參閱http://stackoverflow.com/questions/8002148/c-sharp-generics-contraints-propagation。埃裏克把它放在那裏。 – 2012-01-17 16:56:19

+1

@Jason,我認爲用'but'讀得更好。 – Joey 2012-01-17 16:57:20

+1

@Joey:夠公平的。我只是討厭以'but'開頭的句子,儘管現在使用連詞開始的句子被認爲是正確的。我責怪我的高中英語老師。他是經典英語慣例的守護者。 – 2012-01-17 17:40:52

回答

8

更新:這個問題是the subject of my blog on September 19th, 2011。感謝您的好問題!


爲什麼我必須這樣做,當TBASE已經被限制爲一類,並TDerived被限制爲一TBASE或從它衍生出來?

因爲值類型可以從引用類型派生。 int源自參考類型objectSystem.ValueType,並實現多個接口。這不會使int成爲參考類型。

DerivedClassPool<object>的實例調用SomeMethod<int>是完全合法的,因爲int是從object派生的。

現在,那裏你的批評將被批准的情況下。我們可以構造兩種類型參數相互關聯的情況,即它們在邏輯上只能是引用類型,但只有其中的一種被語言分類爲「已知是引用類型」。

作爲讀者的練習:你能找到一個嗎?對於「已知是參考類型」的精確定義,可能需要仔細閱讀規範的第10.1.5節。

+0

是否有可能創建從引用類型(在C#中)派生的我們自己的值類型? – 2012-01-17 16:58:49

+0

@GeorgeDuckett爲什麼這是相關的? – 2012-01-17 16:59:30

+0

@OskarKjellin:不是,我只是好奇。 :) – 2012-01-17 16:59:50

2

因爲TBase可能是一個接口,因此TDerived可能是一個值類型。

+0

TBase需要成爲一個班級? – 2012-01-17 16:59:04

+1

你確定嗎? http://msdn.microsoft.com/en-us/library/d5x73970.aspx:'類型參數必須是引用類型;這也適用於任何類,接口,委託或數組類型。' – 2012-01-17 16:59:39

+1

不知道。在這種情況下,棘手的'class'的意思是「價值類型」 – 2012-01-17 17:01:34