C# IDictionary<&燃气轮机;相反?
我在外部类中有以下方法C# IDictionary<&燃气轮机;相反?,c#,.net,C#,.net,我在外部类中有以下方法 public static void DoStuffWithAnimals(IDictionary<string, Animal> animals) public static void dostuff with animals(IDictionary animals) 在我的调用代码中,我已经有了一个Dictionary对象,但我不能将其作为此方法的参数传入。那么一个IDictionary不是逆变的吗?我看不出这有什么理由不起作用 我能想到的唯一解决办法
public static void DoStuffWithAnimals(IDictionary<string, Animal> animals)
public static void dostuff with animals(IDictionary animals)
在我的调用代码中,我已经有了一个Dictionary
对象,但我不能将其作为此方法的参数传入。那么一个IDictionary
不是逆变的吗?我看不出这有什么理由不起作用
我能想到的唯一解决办法是:
var animals = new Dictionary<string, Animal>();
foreach(var kvp in lions) {
animals.Add(kvp.Key, kvp.Value);
}
var-anives=newdictionary();
foreach(以狮子为单位的var kvp){
添加(kvp.Key,kvp.Value);
}
如果不创建相同对象的新字典,是否无法将此字典传递到此方法
编辑:
由于这是我的方法,我知道我从字典中使用的唯一成员是
TValue this[TKey key]
的getter,它是IDictionary
的成员,因此在这种情况下,我无法对参数使用“更广泛”的类型。假设派生的
是基
的子类型。然后,Dictionary
不能是Dictionary
的子类型,因为您不能将任何类型为Base
的对象放入Dictionary
中,但是Dictionary
不能是Dictionary
的子类型,因为如果您从Dictionary
中获取对象,它可能不是派生的。因此,Dictionary
的类型参数既不是共变的,也不是逆变的
通常,由于这个原因,可以写入的集合是不变的。如果您有一个不可变的集合,那么它可能是协变的。(如果您有某种只写的集合,它可能是相反的。)
编辑:如果您有一个“集合”,既不能从中获取数据,也不能将数据放入其中,那么它可能是协变的,也可能是逆变的。(这可能也没用。)解决方案方面,您可以这样做,只需传入一个访问器即可:
public static void DoStuffWithAnimals(Func<string, Animal> getAnimal)
{
}
var dicLions = new Dictionary<string, Lion>();
DoStuffWithAnimals(s => dicLions[s]);
public static void DoStuffWithAnimals(Func getAnimal)
{
}
var dicLions=新字典();
动物剂量(s=>dillions[s]);
显然,这对于您的需求来说可能有点简单,但若您只需要几个字典方法,那个么很容易实现
这是另一种在动物之间重复使用代码的方式:
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);
公共类访问器:IAnimalAccessor其中T:Animal
{
私人只读词典;
公共存取器(字典目录)
{
_dict=dict;
}
公共动物获取项(字符串键)
{
返回_dict[键];
}
}
公共接口IAnimalAccessor
{
动物获取项(字符串键);
}
带有动物的公共静态无效剂量(IAnimalAccessor getAnimal)
{
}
var dicLions=新字典();
var访问器=新访问器(dicLions);
动物剂量(存取器);
您可以修改publicstaticvoidostuffwithanimals(IDictionary animals)
以添加泛型约束。以下是在LINQPad中对我有用的东西:
void Main()
{
var lions = new Dictionary<string, Lion>();
lions.Add("one", new Lion{Name="Ben"});
AnimalManipulator.DoStuffWithAnimals(lions);
}
public class AnimalManipulator
{
public static void DoStuffWithAnimals<T>(IDictionary<string, T> 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";
}
}
void Main()
{
var=newdictionary();
添加(“一个”,新的Lion{Name=“Ben”});
动物操作器。与动物(狮子)的接触;
}
公共级动物操纵器
{
带动物的公共静态无效剂量(IDictionary animals)
T:动物
{
foreach(动物中的var kvp)
{
kvp.Value.MakeNoise();
}
}
}
公营动物
{
公共字符串名称{get;set;}
公共虚拟字符串MakeNoise()
{
返回“?”;
}
}
公营狮子:动物
{
公共重写字符串MakeNoise()
{
返回“咆哮”;
}
}
如果字典的接口是只读的(只允许您读取键值对,甚至不允许通过键值提取值),则可以使用out
通用参数修饰符对其进行标记。如果字典的接口是只写的(允许您插入值,但不允许检索值或对其进行迭代),则可以在
通用参数修饰符中使用标记它
因此,您可以自己创建接口并扩展Dictionary类以获得所需的功能。首先,C#中的协方差和逆变仅适用于接口和委托
所以你的问题实际上是关于IDictionary
有了这一点,最简单的方法就是记住,如果类型参数的所有值要么只传入,要么只传出,那么接口只能是co/contra-variant
例如(对冲):
接口IReceiver//note'in'修饰符
{
无效添加(T项);
消除无效(T项);
}
和(协方差):
interface-IGiver//note'out'修饰符
{
T-Get(int-index);
T RemoveAt(int索引);
}
在的情况下,两个类型参数都用于In
和out
容量,这意味着接口不能是协变或逆变的。它是不变的
然而,类确实实现了协变的
这方面的一个重要参考是:
我相信你想要的是协方差,而不是逆方差
Net中的类不能是共变或逆变的,只有接口和委托可以
IDictionary
不能是协变的,因为这将允许您执行以下操作:
IDictionary<string, Sheep> sheep = new Dictionary<string, Sheep>();
IDictionary<string, Animal> animals = sheep;
animals.Add("another innocent sheep", new Wolf());
IDictionary sheep=new Dictionary();
食用动物=绵羊;
添加(“另一只无辜的羊”,新狼());
在.NET4.5中有一个。乍一看,它可能是协变的(另一个新接口是协变的)。不幸的是,它不是,因为它还实现了IEnumerable
,并且KeyValuePair
不是协变的
为了解决这个问题,您可以使用类型参数的约束使您的方法成为泛型的
interface IGiver<out T> // note 'out' modifier
{
T Get(int index);
T RemoveAt(int index);
}
IDictionary<string, Sheep> sheep = new Dictionary<string, Sheep>();
IDictionary<string, Animal> animals = sheep;
animals.Add("another innocent sheep", new Wolf());
void DoStuffWithAnimals<T>(IDictionary<string, T> animals) where T : Animal