在我的示例中,我有许多扩展基类Orange
的类(Pear
,Apple
,Fruit
,...)。
我正在创建一个模型类,其中包含映射到其整数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]''。
我该怎样做我想做的事?
答案 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>
。
在运行时,您不允许直接重新转发Values
,ICollection<Fruit>
到IEnumerable<T>
- 例如IEnumerable<Orange>
。
要解决此问题,您实际上需要按类型遍历Values
收集和向下转换(也可能还要过滤)。
(即使您已经知道您的代码只允许Oranges
进入fruits[typeof(Orange)]
词典,但从类型系统的角度来看,该类型仍然是{\ n} {1}})
根据其他答案,您可以使用多种方式进行此投射和过滤:
ICollection<Fruit>
foreach(T item in Values)
- 如果找到不同的水果,这将会抛出.Cast<T>
- 这将排除不正确类型的项目。有关这些方法的详细信息discussed here