2011-10-29 21 views
3

正如標題所示,我想做到以下幾點,但編譯器不會讓我:如何通用約束添加到非通用類的構造函數在C#

public class MyClass 
{ 
    private List<SomeSupertype> myList; 

    public MyClass<T> (ICollection<T> elements) where T : SomeSupertype 
    { 
     myList = new List<SomeSuperType>(); 
     foreach (SomeSupertype element in elements) { 
      myList.Add (element); 
     } 
    } 
} 

不知何故,似乎沒有可能將一個通用參數添加到本身不是通用類的構造函數中。請注意,MyClass應該是非泛型類型的,因爲客戶端在構建之後不應該區分不同類型的MyClass。

任何人都可以幫我解決這個問題嗎?這可能嗎?它當然是在Java中:)

編輯:我忘了提及我使用.NET 3.5,因此不支持協變泛型。

+5

如果你使用.NET 4,爲什麼不只是有一個非泛型構造函數採用IEnumerable '? 'IEnumerable'1'是協變的,所以'IEnumerable '只要'T:SomeSupertype'都可以轉換爲'IEnumerable '。 –

+0

@Anton:通過一些重新說明和解釋,似乎答案值得 –

+0

是的,協方差可以解決問題。我可能應該提到我正在使用.NET 3.5 – Dino

回答

6

C#中的構造函數不能是泛型的(同上events,properties,destr運營商)。考慮創建一個靜態的通用工廠方法來代替:

public class MyClass 
{ 
    private List<SomeSupertype> myList; 

    private MyClass(List<SomeSupertype> myList) 
    { 
     this.myList = myList; 
    } 

    public static MyClass Create<T>(ICollection<T> elements) 
     where T : SomeSupertype 
    { 
     var myList = new List<SomeSuperType>(elements); 
     foreach (SomeSupertype element in elements) 
     { 
      myList.Add(element); 
     } 
     return new MyClass(myList); 
    } 
} 

即使是在.NET 3.5,你可以使用LINQ使列表創建簡單的,順便說一句:

var myList = elements.Cast<SomeSuperType>().ToList(); 
6

你可以使用工廠模式來解決問題:

public class MyClass 
{ 
    private List<SomeSuperType> myList = new List<SomeSuperType>(); 

    public static MyClass MyClassBuilder<T>(ICollection<T> elements) where T : SomeSuperType 
    { 
     var myClass = new MyClass(); 

     foreach (SomeSuperType element in elements) 
     { 
      myClass.myList.Add(element); 
     } 

     return myClass; 
    } 

    protected MyClass() 
    { 
    } 
} 

或者你可以創建兩個類,像這樣:

// Put all the methods here 
public class MyClass 
{ 
    protected List<SomeSuperType> myList = new List<SomeSuperType>(); 

    protected MyClass() 
    { 
    } 
} 

// This class will define only the generic constructor 
public class MyClass<T> : MyClass where T : SomeSuperType 
{ 
    public MyClass(ICollection<T> elements) 
    { 
     foreach (SomeSuperType element in elements) 
     { 
      myList.Add(element); 
     } 
    } 
} 

(這忽略了,因爲寫的Anton事實,在C#> = 4.0中,您可以簡單地接受IEnumerable<SomeSuperType>並且很高興)

0

在你不能做到這一點C#。這是一件好事,因爲我們不希望構造函數與類不匹配。但仍然有幾種方法可以實現您的目標。

最簡單的方法(如果您使用C#4)是使用IEnumerable而不是ICollection,因爲IEnumerable支持反轉。

public class MyClass 
{ 
    private List<SomeSupertype> myList; 

    public MyClass (IEnumerable<SomeSuperType> elements) 
    { 
     myList = new List<SomeSuperType>(); 
     foreach (SomeSupertype element in elements) { 
      myList.Add (element); 
     } 
    } 
} 

現在,您可以調用構造函數而不考慮將派生類型的集合投射到基類型的集合。

List<SomeDerivedClass> col = new List<SomeDerivedType>(); 
MyClass obj1 = new MyClass(col) 

第二種解決方案,你可以通過使用LINQ投射集合來調用你的構造函數。

MyClass obj1 = new MyClass(col.Cast<SomeSuperClass>()); 

第三種解決方案,你可以創建靜態泛型方法來構建你的類的新對象。

public static MyClass Construct<T>(ICollection<T> elements) where T : ClassA 
{ 
    return new MyClass(elements.Cast<ClassA>().ToArray()); 
} 

第四的解決方案,你可以做一個泛型類正如有人已經指出的那樣,從基類派生的。