创建泛型类型的字典

时间:2017-11-18 08:19:47

标签: c# .net dictionary generics

在我的示例中,我有许多扩展基类Orange的类(PearAppleFruit,...)。

我正在创建一个模型类,其中包含映射到其整数ID的每种Fruit类型的字典。我想避免像这样制作许多字段变量:

Dictionary<int, Orange> _oranges = new Dictionary<int, Orange>();

我想我可以创建一个“通用”词典,在其中我将其他词典映射到Fruit类型:

Dictionary<Type, Dictionary<int, Fruit>> _fruits = new Dictionary<Type, Dictionary<int, Fruit>>();

要插入此结构,我使用如下方法:

public void Insert(Fruit fruit)
{
    _fruits[fruit.GetType()][fruit.Id] = fruit;
}

当我尝试检索存储的值时出现问题,如此方法:

public IEnumerable<T> GetFruits<T>() where T : Fruit
{
    return (IEnumerable<T>) _fruits[typeof(T)].Values.ToArray();
}

将被称为GetFruits<Orange>()。演员失败并出现此错误:

  

System.InvalidCastException:'无法转换类型的对象   'Example.Fruit []'输入   'System.Collections.Generic.IEnumerable`1 [Example.Orange]''。

我该怎样做我想做的事?

3 个答案:

答案 0 :(得分:2)

我认为你只需要使用Cast<T>投射它。

return _fruits[typeof(T)].Values.Cast<T>();

使用(IEnumerable<T>)进行投射不起作用,因为它会投射整个事物。您可能已经知道这一点:List<object>无法投放到List<int>。这里也发生了同样的现象。

因此,我们应该使用Cast<T>。此方法将枚举的每个元素强制转换为指定的类型,并返回生成的可枚举。

答案 1 :(得分:1)

您可以使用OfType方法:

var _fruits = new Dictionary<Type, Dictionary<int, Fruit>>();

public IEnumerable<T> GetFruits<T>() where T : Fruit
{
    return _fruits.OfType<T>().ToArray();
}

答案 2 :(得分:1)

您收到错误的原因是因为Values最里面的词典中_fruits的类型本身就是基类Fruit的地图:

Dictionary<int, Fruit>

具体来说,Values property is defined as ICollection<T>

在运行时,您不允许直接重新转发ValuesICollection<Fruit>IEnumerable<T> - 例如IEnumerable<Orange>

要解决此问题,您实际上需要按类型遍历Values收集和向下转换(也可能还要过滤)。

(即使您已经知道您的代码只允许Oranges进入fruits[typeof(Orange)]词典,但从类型系统的角度来看,该类型仍然是{\ n} {1}})

根据其他答案,您可以使用多种方式进行此投射和过滤:

  • 已过滤的foreach,ICollection<Fruit>
  • foreach(T item in Values) - 如果找到不同的水果,这将会抛出
  • .Cast<T> - 这将排除不正确类型的项目。

有关这些方法的详细信息discussed here