2012-12-06 53 views
2

我想打電話給一個定義類似的方法如下(簡化,以避免混淆):通用多約束

public static void Register<T>(T value) where T : BaseClass, IInterface 

這工作得很好,只要我有一個類實例定義了這些價值。當我將一個`BaseClass'傳入一個方法然後嘗試在上面的聲明中使用該實例時,就會出現這個問題。例如:

public class MyClass 
{ 
    public MyClass(BaseClass value) 
    { 
     Register(value); 
    } 
} 

我可以通過並同時實現BaseClass的和IInterface到構造函數的類的實例,但是,當我嘗試使用該值在Register方法我得到一個編譯錯誤,指出:

類型'BaseClass'不能用作通用類型或方法'Register(T)'中的類型參數'T'。沒有從'BaseClass'到'IInterface'的隱式引用轉換。

如果我更改類型在構造函數中,像這樣:

public class MyClass 
{ 
    public MyClass(IInterface value) 
    { 
     Register(value); 
    } 
} 

我得到一個錯誤,指出:

類型「IInterface」不能用作類型參數「T」在通用類型或方法'Register(T)'中。沒有從'IInterface'到'BaseClass'的隱式引用轉換。

這看起來有點像22。 有沒有一種方法可以定義參數來表明它必須實現BaseClass和IInterface?

回答

5

當我寫這個問題時,我想出了答案,並認爲我會發布它,而不是刪除問題。

我只需要重新定義類:

public class MyClass<T> where T : BaseClass, IInterface 
{ 
    public MyClass(T value) 
    { 
     Register(value); 
    } 
} 
1

馬特給出的解決方案是情況下一個簡單的答案,其中沒有必要存儲傳入的一個字段或集合對象。如果你需要堅持傳入的對象,事情會變得更難很多。對於一個SomeClass<T>,其中T滿足多個約束,以存儲T類項目並將它們作爲泛型傳遞給具有這種約束的例程,但是如果一個類具有方法SomeMethod<TParam>(TParam thing),其中TParam:IFoo,BaseBar,則它將不具有任何類型的字段TParam。它可以存儲thingIFoo型或BaseBar的領域,但除非BaseBar實現IFoo,或所有傳入的情況下,會從一個特定BaseBar衍生物,其實現IFoo推導,有沒有辦法來指定字段的類型將滿足約束條件(如果每個實例都來源於實現IFoo的一個特定衍生物,則可以簡單地將該類型用作單個約束,或者就此而言完全不用泛型 - 只是將其用作參數類型)。

有辦法解決這些問題,無論是使用反射,我稱爲ISelf<T>的接口模式,或一些棘手的嵌套回調接口。但是,在某些情況下,最好爲採用雙約束參數的方法提供替代方法(使方法接受一個約束類型的參數,將其轉換爲其他類型,並接受缺乏編譯時安全性) 。

+0

這是我最初嘗試去的路徑。很高興知道這是一條艱難的道路,我有一個更容易達到的路徑。 –