为什么一个接口实现需要转换而另一个不需要?

时间:2013-11-11 10:22:24

标签: c# generics interface covariance

当我遇到以下情况时,我今天正在使用接口做一些工作。鉴于这两个简单的接口:

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

我怀疑这里有一些神奇的类型转换,因此似乎与共同/逆转有关,但我不太清楚究竟发生了什么。

5 个答案:

答案 0 :(得分:3)

Dictionary<int, IItem>未实施ICollection<IItem>。就这么简单。

实现该接口是没有意义的,因为如果不指定密钥就无法添加到字典中。界面没有意义。

这是一个运行时错误,因为items可以引用Dictionary的子类,以便强制转换为有效。

答案 1 :(得分: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>>

答案 2 :(得分:0)

BasicInventory1 {}返回items.ValuesBasicInventory2,您只返回items.Values会返回ICollection,因此不需要演员。

MSDN:

答案 3 :(得分:0)

此代码不是有效的,并且始终会生成运行时错误:

    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

答案 4 :(得分:-1)

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