IDictionary 逆转?
我在外部类中有以下方法
public static void DoStuffWithAnimals(IDictionary animals)
在我的调用代码中,我已经有了一个Dictionary
对象,但我无法将此作为此方法的参数传递。 那么IDictionary
不是逆变的吗? 我看不出为什么这不起作用的任何理由。
我能想到的唯一解决方案是:
var animals = new Dictionary(); foreach(var kvp in lions) { animals.Add(kvp.Key, kvp.Value); }
有没有办法将此字典传递给此方法,而无需创建相同对象的新字典?
编辑:
因为这是我的方法,我知道我在字典中使用的唯一成员是TValue this[TKey key]
的getter TValue this[TKey key]
,它是IDictionary
的成员,所以在这种情况下,我无法为参数使用’更宽’类型。
解决方案明智的是你可以做这样的事情,只需传入一个存取器:
public static void DoStuffWithAnimals(Func getAnimal) { } var dicLions = new Dictionary(); DoStuffWithAnimals(s => dicLions[s]);
显然,这可能对您的需求来说有点简单,但如果您只需要几个字典方法,那么很容易实现这一点。
这是另一种让您在动物之间重复使用代码的方法:
public class Accessor : IAnimalAccessor where T : Animal { private readonly Dictionary _dict; public Accessor(Dictionary 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(); var accessor = new Accessor(dicLions); DoStuffWithAnimals(accessor);
假设Derived
是Base
的子类型。 然后, Dictionary
不能是Dictionary
的子类型,因为您不能将任何Base
类型的对象放入Dictionary
,但Dictionary
不能是Dictionary
的子类型Dictionary
因为如果你从Dictionary
获取一个对象,它可能不是Derived
。 因此, Dictionary
在其类型参数中既不是共同变量也不是逆变量。
通常,由于这个原因,您可以写入的集合是不变的。 如果你有一个不可变的集合,那么它可能是协变的。 (如果你有某种只写的集合,它可能是逆变的。)
编辑:如果你有一个“集合”,你既不能从中获取数据也不能将数据输入,那么它可能既有共变,也有逆变。 (它也可能没用。)
首先,C#中的协方差和逆变仅适用于接口和委托。
所以你的问题实际上是关于IDictionary
。
有了这一点,最简单的方法就是记住,如果类型参数的所有值都只是传入,或者只是传递出来,那么接口只能是共同变体。
例如(协方差):
interface IReceiver // note 'in' modifier { void Add(T item); void Remove(T item); }
和(逆变):
interface IGiver // note 'out' modifier { T Get(int index); T RemoveAt(int index); }
我永远不会记得哪一个是协变的,哪个是逆变的,但最终无所谓,只要你记住这个进/出的区别。
在IDictionary
的情况下,两种类型参数都用于in和out容量,这意味着接口不能是协变的或逆变的。 它是不变的。
但是,类Dictionary
确实实现了IEnumerable
,它是协变的。
您可以修改public static void DoStuffWithAnimals(IDictionary
以添加通用约束。 这是LINQPad中适合我的东西:
void Main() { var lions = new Dictionary(); lions.Add("one", new Lion{Name="Ben"}); AnimalManipulator.DoStuffWithAnimals(lions); } public class AnimalManipulator { public static void DoStuffWithAnimals(IDictionary animals) where T : Animal { foreach (var kvp in animals) { kvp.Value.MakeNoise(); } } } public class Animal { public string Name {get;set;} public virtual string MakeNoise() { return "?"; } } public class Lion : Animal { public override string MakeNoise() { return "Roar"; } }
- 我相信你想要的是协方差,而不是逆变。
- .Net中的类不能是共变或逆变,只有接口和委托才能。
-
IDictionary
不能协变,因为这可以让你做类似的事情:IDictionary
sheep = new Dictionary (); IDictionary animals = sheep; animals.Add("another innocent sheep", new Wolf()); -
.Net 4.5中有
IReadOnlyDictionary
。 乍一看它可能是协变的(另一个新接口,IReadOnlyList
是协变的)。 不幸的是,它不是,因为它还实现了IEnumerable
和> KeyValuePair
不是协变的。 -
要解决此问题,您可以使用type参数的约束使您的方法通用:
void DoStuffWithAnimals
(IDictionary animals) where T : Animal
如果字典的接口是只读的(允许您只读取键值对,甚至不能允许通过其键拉取值),则可以使用out
generic参数修饰符进行标记。 如果字典的接口是只写的(允许您插入值,但不能检索它们或迭代它们),则可以使用in
generic参数修饰符标记它。
因此,您可以自己创建接口并扩展Dictionary类,以获得所需的function。