为什么可以';t我通过列表<;T>;到泛型构造函数参数,尽管满足了所有约束
本文关键字:泛型 参数 构造函数 约束 满足 为什么 lt 列表 gt | 更新日期: 2023-09-27 18:28:04
我有以下代码:
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>
等类。
将泛型约束更改为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;
}
}
您的方法的问题是,您假设可以将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
的实例中调用代码传递,而不是自己创建它。在这种情况下,您只需删除默认构造函数。
我相信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
上。