创建泛型类型的字典
在我的示例中,我有很多扩展基类Fruit
的类(Orange
,Pear
,Apple
,...)。创建泛型类型的字典
我正在创建一个模型类,其中包含映射到其整数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: 'Unable to cast object of type 'Example.Fruit[]' to type 'System.Collections.Generic.IEnumerable`1[Example.Orange]'.'
我该怎么做我想做的事?
我想你只需要使用Cast<T>
就可以了。
return _fruits[typeof(T)].Values.Cast<T>();
使用(IEnumerable<T>)
来投射不起作用,因为它会投射整个东西。您可能已经知道:List<object>
不能铸造到List<int>
。这里发生同样的现象。我们应该使用Cast<T>
。此方法将把枚举的每个元素转换为指定的类型,并返回结果的枚举。
您可以使用OfType
方法:
var _fruits = new Dictionary<Type, Dictionary<int, Fruit>>();
public IEnumerable<T> GetFruits<T>() where T : Fruit
{
return _fruits.OfType<T>().ToArray();
}
为什么你的错误是因为Values
在_fruits
最里面的词典类型本身是地图的基类Fruit
的原因:
Dictionary<int, Fruit>
具体而言,Values property is defined as ICollection<T>
。
在运行时,您不允许直接重写Values
,这是一个ICollection<Fruit>
到IEnumerable<T>
- 例如, IEnumerable<Orange>
。
要解决此问题,您将有效地需要遍历Values
集合,并按类型遍历(可能还会筛选)。
(即使你“知道”你的代码只允许Oranges
到fruits[typeof(Orange)]
字典,从类型系统的角度来看,该类型仍然是ICollection<Fruit>
)
按其他的答案,你可以使用任意数量的方式来做到这一点铸造和过滤:
- 一个过滤的foreach,
foreach(T item in Values)
-
.Cast<T>
- 然而,这将抛出,如果以某种方式不同的水果中发现 -
.OfType<T>
- 这会排除错误类型的项目。
有一个关于这些方法更详细地discussed here
另外/可替代地,也可以使用['OfType'](https://*.com/a/41951319/314291)来过滤的类型,并避免可能的InvalidCast异常 – StuartLC
谢谢,这正是我想要的,我明白为什么我的代码不工作之前:) –