0

今天我正在使用接口做一些工作,当我遇到以下场景时。给定这两个简单的接口:

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.

我怀疑这里有一些神奇的类型转换,因此似乎与协/逆变有关,但我不太明白到底发生了什么。

4

5 回答 5

3

Dictionary<int, IItem>不执行ICollection<IItem>。就那么简单。

实现该接口是没有意义的,因为您不能在不指定键的情况下添加到字典。界面没有意义。

这是一个运行时错误,因为项目可能引用 Dictionary 的子类,因此强制转换可能是有效的。

于 2013-11-11T10:27:27.000 回答
2

我认为如果您要添加.Values到第二个示例,则不需要演员表

public class BasicInventory2 : IInventory
{
    private Dictionary<int, IItem> items;
    public ICollection<IItem> Items
    {
       get { return items.Values; }
    }
}

这是因为 items 是一个 Dictionary 并且实现了ICollection<KeyValuePair<TKey, TValue>>.

于 2013-11-11T10:26:34.330 回答
0

BasicInventory1你返回items.Values中,BasicInventory2你只返回items.Values返回 a ICollection,因此不需要强制转换。

MSDN:

于 2013-11-11T10:26:49.827 回答
0

此代码无效,将始终生成运行时错误:

    public class BasicInventory2 : IInventory
    {
        private Dictionary<int, IItem> items = new Dictionary<int, IItem>();

        public ICollection<IItem> Items
        {
            get
            {
                return (ICollection<IItem>) items;
            }
        }
    }

A Dictionary<int, IItem>不实现ICollection<IItem>,而从返回的类型Dictionary<int, IItem>.Values 实现

所以答案是:

第一种情况没问题,因为Values类型正确。

在第二种情况下,编译器知道您正在尝试返回错误的类型,因此它会给您一个编译错误。

如果你用 case 覆盖错误,你会得到一个 runtime BadCastException

于 2013-11-11T10:32:23.357 回答
-1

在第二个代码中,您使用字典作为返回值,而在第一个代码中,您使用这些值。Dictionary<int,IItems>继承自ICollection<KeyValuePair<int,IItems>>因此 is not ICollection<IItems>。因此,您需要演员表。

于 2013-11-11T10:27:44.363 回答