受限类型的通用集合
Generic collection of restricted types
我有一个 class 需要以下定义:
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 class 定义的 "new()" 类型限制,但此 class 中的代码需要它。我知道我可以通过使用特定的 class 类型来解决这个问题,该类型将包含一个无参数构造函数,例如 :
private Dictionary<Type, Table<ClientTable>> _tableDictionary;
但是必须支持不同类型的table,这也是它们都实现 IRowDef 的原因。
有人知道我该如何解决这个问题吗?
问题是您需要 table 的集合,但是 Table<X>
与 Table<Y>
不兼容,WhateverCollection<Table<X>>
与 WhateverCollection<Table<X>>
不兼容WhateverCollection<Table<Y>>
,即使X
是接口类型,Y
实现了这个接口。
为什么会这样?假设你有
List<IAnimal> animals = new List<Elefant>();
animals.Add(giraffe); // Ooops!
Put that in your pipe and smoke it!
// DOES NOT WORK!
T<Base> b = new T<Derived>(); // T<Derived> is not assignment compatible to T<Base>!!!
但是
Base b = new Derived(); // OK
诀窍是有两个 table classes:一个非泛型基础 class 和一个派生泛型 class:
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
基础 class 并让 Table<T>
实现 ITable
然后将字典声明为 Dictionary<Type, ITable>
.
您可以删除 new()
约束并使用 Activator.CreateInstance<T>()
创建新对象。这将检查从编译时转移到运行时。 C# 编译器将 new T()
转换为 Activator.CreateInstance
调用。
Olivier Jacof-Descombes 提出了一种可能的方法。另一个(只适用于可以修改Table
class):
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;
我有一个 class 需要以下定义:
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 class 定义的 "new()" 类型限制,但此 class 中的代码需要它。我知道我可以通过使用特定的 class 类型来解决这个问题,该类型将包含一个无参数构造函数,例如 :
private Dictionary<Type, Table<ClientTable>> _tableDictionary;
但是必须支持不同类型的table,这也是它们都实现 IRowDef 的原因。
有人知道我该如何解决这个问题吗?
问题是您需要 table 的集合,但是 Table<X>
与 Table<Y>
不兼容,WhateverCollection<Table<X>>
与 WhateverCollection<Table<X>>
不兼容WhateverCollection<Table<Y>>
,即使X
是接口类型,Y
实现了这个接口。
为什么会这样?假设你有
List<IAnimal> animals = new List<Elefant>();
animals.Add(giraffe); // Ooops!
Put that in your pipe and smoke it!
// DOES NOT WORK! T<Base> b = new T<Derived>(); // T<Derived> is not assignment compatible to T<Base>!!!
但是
Base b = new Derived(); // OK
诀窍是有两个 table classes:一个非泛型基础 class 和一个派生泛型 class:
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
基础 class 并让 Table<T>
实现 ITable
然后将字典声明为 Dictionary<Type, ITable>
.
您可以删除 new()
约束并使用 Activator.CreateInstance<T>()
创建新对象。这将检查从编译时转移到运行时。 C# 编译器将 new T()
转换为 Activator.CreateInstance
调用。
Olivier Jacof-Descombes 提出了一种可能的方法。另一个(只适用于可以修改Table
class):
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;