受限类型的通用集合

时间:2015-10-11 13:17:29

标签: c# generics collections covariance

我有一个班级需要以下定义:

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必须是非抽象的并且具有无参数构造函数。我知道它来自&#34; new()&#34;对类类定义的类型限制,但是此类中的代码需要它。我知道我可以通过使用包含参数less constructor的特定类类型来解决这个问题,例如:

private Dictionary<Type, Table<ClientTable>> _tableDictionary;

但必须支持不同类型的表,这就是为什么所有这些表都实现IRowDef的原因。

有人知道如何解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

问题是您需要一组表格,但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实现{ {1}}然后将字典声明为Dictionary<Type, ITable>

答案 1 :(得分:0)

您可以删除new()约束并使用Activator.CreateInstance<T>()创建新对象。这将检查从编译时移动到运行时。无论如何,C#编译器将new T()转换为Activator.CreateInstance调用。

答案 2 :(得分:0)

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;