首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >IDictionary<,>反方差?

IDictionary<,>反方差?
EN

Stack Overflow用户
提问于 2012-10-11 14:06:05
回答 6查看 3.7K关注 0票数 20

在外部类中有以下方法

代码语言:javascript
运行
复制
public static void DoStuffWithAnimals(IDictionary<string, Animal> animals)

在我的调用代码中,我已经有了一个Dictionary<string, Lion>对象,但是我不能将它作为该方法的参数传递进来。所以IDictionary<,>不是反变体吗?我看不出有什么理由不应该这样做。

我唯一能想到的解决办法是:

代码语言:javascript
运行
复制
var animals = new Dictionary<string, Animal>();

foreach(var kvp in lions) {
    animals.Add(kvp.Key, kvp.Value);
}

如果不创建相同对象的新字典,就无法将此字典传递到此方法中吗?

编辑:

因为这是我的方法,我知道我从字典中使用的唯一成员是TValue this[TKey key]的getter,它是IDictionary<TKey, TValue>的一个成员,所以在这个场景中,我不能对参数使用“更宽”的类型。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-10-11 14:17:32

就解决方案而言,您可以这样做,只需传入一个访问器即可:

代码语言:javascript
运行
复制
    public static void DoStuffWithAnimals(Func<string, Animal> getAnimal)
    {
    }

    var dicLions = new Dictionary<string, Lion>();
    DoStuffWithAnimals(s => dicLions[s]);

显然,对于您的需要,这可能有点简单,但是如果您只需要几个字典方法,就可以很容易地做到这一点。

这是另一种让你在动物之间重复使用代码的方法:

代码语言:javascript
运行
复制
    public class Accessor<T> : IAnimalAccessor where T : Animal
    {
        private readonly Dictionary<string, T> _dict;

        public Accessor(Dictionary<string, T> dict)
        {
            _dict = dict;
        }

        public Animal GetItem(String key)
        {
            return _dict[key];
        }
    }

    public interface IAnimalAccessor
    {
        Animal GetItem(string key);
    }

    public static void DoStuffWithAnimals(IAnimalAccessor getAnimal)
    {
    }

    var dicLions = new Dictionary<string, Lion>();
    var accessor = new Accessor<Lion>(dicLions);
    DoStuffWithAnimals(accessor);
票数 7
EN

Stack Overflow用户

发布于 2012-10-11 14:25:00

首先,C#中的协方差和逆方差只适用于接口和委托。

所以你的问题真的是关于IDictionary<TKey,TValue>的。

在这种情况下,最简单的做法就是记住,如果一个类型参数的所有值都只是传入,或者只是传递出去,那么接口只能是协/对变量。

例如(反差额):

代码语言:javascript
运行
复制
interface IReceiver<in T> // note 'in' modifier
{
    void Add(T item);
    void Remove(T item);
}

和(协方差):

代码语言:javascript
运行
复制
interface IGiver<out T> // note 'out' modifier
{
    T Get(int index);
    T RemoveAt(int index);
}

IDictionary的情况下,这两种类型的参数都是在inout容量中使用的,这意味着接口不能是协变的或反变的。它是不变的。

但是,类Dictionary确实实现了协变的IEnumerable

这方面的一个重要参考是:

https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

票数 9
EN

Stack Overflow用户

发布于 2012-10-11 14:10:07

假设DerivedBase的一个子类型。然后,Dictionary<Base>不能是Dictionary<Derived>的子类型,因为您不能将任何Base类型的对象放入Dictionary<Derived>,但是Dictionary<Derived>不能是Dictionary<Base>的子类型,因为如果从Dictionary<Base>中获取对象,它可能不是Derived。因此,Dictionary在其类型参数中既不是协变量也不是反变体。

通常,由于这个原因,可以写入的集合是不变的。如果您有一个不变的集合,那么它可能是协变的。(如果您有某种只写的集合,它可能是相反的。)

编辑:如果您有一个既不能从数据中获取数据,也不能将数据放入的“集合”,那么它可能是协变量和反变体。(这也可能毫无用处。)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12841458

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档