受限制类型的泛型集合
本文关键字:集合 泛型 类型 受限制 | 更新日期: 2023-09-27 18:17:13
我有一个类,它需要以下定义:
public class Table<T> : ObservableCollection<T> where T : IRowDef, new()
我想创建它的集合,并与实例映射类型。所以我试试:
public sealed class TableCollection : IEnumerable<Table<IRowDef>>
{
private Dictionary<Type, Table<IRowDef>> _tableDictionary;
public Table<IRowDef> GetTable<T>() where T : IRowDef, new()
{
Table<IRowDef> table = null;
if (_tableDictionary.ContainsKey(typeof(T)))
{
table = _tableDictionary[typeof(T)];
}
else
{
table = new Table<IRowDef>();
_tableDictionary.Add(typeof(T), table);
}
return table;
}
...
}
但是我不能让它工作。下面几行和其他几行给出了相同的错误:
private Dictionary<Type, Table<IRowDef>> _tableDictionary;
翻译后的错误告诉IRowDef必须是非抽象的,并且有一个无参数的构造函数。我知道它来自Table类定义上的"new()"类型限制,但它是这个类内部代码所需要的。我知道我可以通过使用一个包含无参数构造函数的特定类类型来解决这个问题,例如:
private Dictionary<Type, Table<ClientTable>> _tableDictionary;
但是必须支持不同类型的表,这也是为什么它们都实现了IRowDef的原因。
有谁知道我怎么解决这个问题吗?
问题是您需要一个表集合,但是Table<X>
与Table<Y>
不兼容,WhateverCollection<Table<X>>
与WhateverCollection<Table<Y>>
不兼容,即使X
是一个接口类型并且Y
实现了该接口。
为什么?假设你有
List<IAnimal> animals = new List<Elefant>();
animals.Add(giraffe); // Ooops!
把它放进你的烟斗里抽吧!
// DOES NOT WORK! T<Base> b = new T<Derived>(); // T<Derived> is not assignment compatible to T<Base>!!!
,
Base b = new Derived(); // OK
技巧是有两个表类:一个非泛型基类和一个派生泛型类:
public abstract class Table
{}
public class Table<T> : Table
where T : IRowDef, new()
{
private readonly ObservableCollection<T> _rows = new ...;
}
现在可以声明
private Dictionary<Type, Table> _tableDictionary;
或者如果你想坚持从一个可观察对象集合中派生,声明一个(非泛型!)ITable
接口,而不是Table
基类,让Table<T>
实现ITable
,然后将字典声明为Dictionary<Type, ITable>
。
您可以删除new()
约束并使用Activator.CreateInstance<T>()
来创建新对象。这将把检查从编译时移到运行时。c#编译器将new T()
转换为Activator.CreateInstance
调用。
Olivier Jacof-Descombes提出了一种可能的方法。另一个(仅适用于可以修改Table
类):
public interface ITable
{
//Some needed methods, f,e,
IRowDef GetSth();
}
:
public class Table<T> : ..., ITable where T : IRowDef, new()
{
IRowDef ITable.GetSth()
{
return (IRowDef)this.GetSthImplInsideTable(); // cast is optional
}
public T GetSthImplInsideTable() { /* impl */ }
}
你可以这样写:
private Dictionary<T, ITable> _tablesDict;