[英]Why can't I pass List<T> to a generic constructor parameter although all contraints are met?
我有以下代碼:
public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>
{
private readonly TCollection _collection;
public SampleClass() : this(new List<T>()) { }
public SampleClass(TCollection collection)
{
_collection = collection;
}
}
不幸的是,包含默認構造函數public SampleClass() : this(new List<T>()) { }
無法編譯。 錯誤消息說: 參數1:無法從'System.Collections.Generic.List'轉換為'TCollection' 。
為什么會這樣? List<T>
實際上符合我放置在TCollection泛型上的所有約束:它是一個實現IList<T>
和IReadOnlyList<T>
。
非常感謝你的幫助。
編輯:更新了代碼,因為它包含錯誤。
為什么會這樣?
問題是我可以寫這樣的代碼:
class X : IList<int>, IReadOnlyList<int>
{
...
}
然后嘗試使用它:
var instance = new SampleClass<int, X>();
但是沒有從List<int>
到X
轉換。
此方案的可能性是您收到編譯器錯誤消息的原因:
參數1:無法從'System.Collections.Generic.List'轉換為'TCollection'。
要獲得您正在尋找的“ List<T>
默認”行為,您可以擺脫該默認構造函數並將其替換為以下內容:
static class SampleClass
{
public static SampleClass<T, List<T>> Create<T>()
{
return new SampleClass<T, List<T>>(new List<T>());
}
}
這是一個類似於Tuple
靜態類的模式,其靜態Tuple.Create
泛型方法和非靜態Tuple<T1>
, Tuple<T1, T2>
等類。
您的方法的問題是您假設您可以將List<T>
分配給類型為TCollection
的引用,而實際上並不知道TCollection
是什么。 您可以在這里使用兩種方法。 前者更接近你現在擁有的,而后者允許你編寫一個更容易在更廣泛的場景中使用的類。
對TCollection
使用new
約束。 雖然你仍然不知道TCollection
的類型,編譯器要求類型有一個默認的構造函數,允許你寫這個:
public class SampleClass<T, TCollection> where TCollection : IList<T>, IReadOnlyList<T>, new() { public SampleClass() : this(new TCollection()) { } public SampleClass(TCollection collection) { ... } }
要求在TCollection
的實例中調用代碼傳遞,而不是自己創建它。 在這種情況下,您只需刪除默認構造函數。
將泛型約束更改為TCollection
並添加new()
約束。 然后,您可以使用new TCollection()
初始化類
public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>, new()
{
private readonly TCollection _collection;
public SampleClass() : this(new TCollection()) { }
public SampleClass(TCollection collection)
{
_collection = collection;
}
}
我相信Sam Harwell有部分答案,你真的希望TCollection
是包含T
元素的東西,所以你應該有:
public class SampleClass<T, TCollection>
where TCollection : class, IList<T>, IReadOnlyList<T>
但是,這還不足以處理這樣一個事實,即您希望有一個無參數構造函數將new List<T>()
傳遞給采用TCollection
參數的構造函數。 某些東西可能是一個TCollection
而不是List<T>
或它的基礎,因此沒有足夠的約束來保證這將起作用。
有三種可能的方法。 一,完全擺脫無參數構造函數:
public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>, new()
{
private readonly TCollection _collection;
public SampleClass(TCollection collection)
{
_collection = collection;
}
}
二,將傳入的集合存儲為List<T>
並堅持認為TCollection
要么是它,要么是從它派生的(不太可能有用):
public class SampleClass<T, TCollection> where TCollection : List<T>
{
private readonly List<T> _collection;
public SampleClass() : this(new List<T>()) { }
public SampleClass(TCollection collection)
{
_collection = collection;
}
}
三,堅持認為TCollection
是一個帶無參數構造函數的類,並使用:
public class SampleClass<T, TCollection> where TCollection : class, IList<T>, IReadOnlyList<T>, new()
{
private readonly TCollection _collection;
public SampleClass() : this(new TCollection()) { }
public SampleClass(TCollection collection)
{
_collection = collection;
}
}
TCollection
是你定義的一個類?
List<T>
實現:
public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>,
IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
TCollection
是否實現IList
, ICollection
或繼承List<T>
或Collection<T>
的基類? 您的TCollection
必須實現或繼承其中一個以刪除編譯錯誤。
您還需要將類TCollection
更改為TCollection<T>
,以便接受通常定義的new List<T>
。 通用需要在某處傳遞給您的集合。
當然,除非你將約束放在定義TCollection
上。 您可能需要注意的是,您對通用<T>
而不是TCollection
設置了約束。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.