我今天正在做一些接口工作,当我遇到以下情况时。给定这两个简单的接口:
public interface IItem { }
public interface IInventory
{
ICollection<IItem> Items { get; }
}
我做了一个简单的类来实现IInventory
,并注意到这个实现完全可以写成:
public class BasicInventory1 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return items.Values; }
}
}
但是,此实现需要强制转换:
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return (ICollection<IItem>)items; }
}
}
为什么一个需要演员,而另一个不需要?检查在这两种情况下返回的两个集合的对象类型,可以确认它们实际上都实现了ICollection
。
我怀疑这里有一些魔术类型的转换正在进行,因此似乎与协变/逆变有关,但我不太明白到底发生了什么。
Dictionary<int, IItem>
没有实现ICollection<IItem>
。就这么简单。
实现该接口是没有意义的,因为如果不指定键,就无法添加到字典中。界面没有意义。
这是一个运行时错误,因为项可以引用字典的子类,以便强制转换可能有效。
第二个示例中添加.Values
,则不需要演员表
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return items.Values; }
}
}
这是因为 items 是一个字典,它实现了ICollection<KeyValuePair<TKey, TValue>>
.
此代码无效,并且将始终生成运行时错误:
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items = new Dictionary<int, IItem>();
public ICollection<IItem> Items
{
get
{
return (ICollection<IItem>) items;
}
}
}
Dictionary<int, IItem>
不实现ICollection<IItem>
,而从Dictionary<int, IItem>.Values
返回的类型实现。
所以答案是:
第一种情况是可以的Values
因为类型正确。
在第二种情况下,编译器知道您正在尝试返回错误的类型,因此它会给您一个编译错误。
如果用案例覆盖错误,则会得到运行时BadCastException
。
在BasicInventory1
中,你返回items.Values
BasicInventory2
你只返回items
。 .Values
返回一个ICollection
,所以不需要强制转换。
MSDN:
- 词典
- 值
在第二个代码中,使用字典作为返回值,而在第一个代码中使用值。 因此,Dictionary<int,IItems>
从ICollection<KeyValuePair<int,IItems>>
继承ICollection<IItems>
。因此,您需要演员阵容。