C# &引用;“通用”;类型参数/类型参数中的继承
假设我有一个函数C# &引用;“通用”;类型参数/类型参数中的继承,c#,C#,假设我有一个函数 DoSomething(字典目录) 为什么不能称之为 DoSomething(新字典()) 由于int和string都继承自对象,因此我希望这能起作用。我知道我可以把这扩展到 DoSomething(字典目录) ,但是为什么第一个选项不起作用呢?这是因为字典不是字典 要实现这一点,类类型字典需要在TKey和TValue中都是协变的,协变需要与值类型一起工作(装箱) 首先,在.NET中,泛型类类型总是不变的。只有接口类型和委托类型可以是共变或逆变的 其次,词典在语义上不是协变的。
DoSomething(字典目录)
为什么不能称之为
DoSomething(新字典())
由于int
和string
都继承自对象
,因此我希望这能起作用。我知道我可以把这扩展到
DoSomething(字典目录)
,但是为什么第一个选项不起作用呢?这是因为
字典
不是字典
要实现这一点,类类型字典
需要在TKey
和TValue
中都是协变的,协变需要与值类型一起工作(装箱)
首先,在.NET中,泛型类类型总是不变的。只有接口类型和委托类型可以是共变或逆变的
其次,词典
在语义上不是协变的。例如,你可以说:
myDict.Add(new Elephant(), new BankCustomer());
如果myDict
实际上是Dictionary
变量中的一个(运行时)Dictionary
,那就不太好了
现在,自.NET4.5以来,一些“非字典”类型实现了协变接口,如
IReadOnlyList
。您可能希望类似的接口IReadOnlyDictionary
也是协变的。但事实并非如此(下面Servy的第一条评论给出了原因)。所以你没有希望。仅仅因为B
是a
的一个子类型,并不意味着List
是List的一个子类型,因为Dictionary
对于两个泛型参数的类型都是不变的
在C#中,所有泛型参数都是不变的。对于接口,泛型参数只能是协变或逆变的
IDictionary
接口对于这两种类型的参数也不能是协变或逆变的。除了全部传入外,还通过Keys
属性传入键,并且除了全部传入外,还使用Add
传入值。因为这两种类型都用作输入和输出,所以这些类型必须是不变的
和协方差/逆方差不适用于值类型;它只能用于引用类型
仅举一个简单的例子,如果允许您进行这样的转换,那么我将能够调用字典上的dict.Add(“非int”,new Foo())
。我现在添加了一个不是int的键和一个不是字符串的值。因为允许强制转换将允许使用与签名不匹配的类型,所以它不起作用。仅仅因为字典
是不协变的
如果可能的话,那么下面的行将抛出一个运行时异常
Dictionary<object, object> dict = new Dictionary<string, string>();
dict["hello"] = new SomeOtherObject();
Dictionary dict=new Dictionary();
dict[“hello”]=新的SomeOtherObject();
由于在构建过程中不会收到警告,因此最终会出现间歇性错误。您可以使用它,因为该类型在这种情况下不是协变或逆变的。举个例子:
var dict=new Dictionary<int,string>();
DoSomething(dict);
DoSomething(Dictionary<object, object> dict)
{
var now=DateTime.Now;
dict[now]=now;
}
var dict=newdictionary();
剂量测定法(dict);
DoSomething(字典dict dict)
{
var now=DateTime.now;
dict[现在]=现在;
}
在您的场景中,您现在已经在[int,string]字典中添加了一个DateTime
IReadOnlyDictionary
必须对TValue
保持不变,因为TryGetValue
将其用作out
参数,该参数不能因使用的类型而异TKey
必须是不变的,因为该键使用ContainsKey
作为输入,并通过Keys
作为输出。如果TryGetValue
的签名已更改,以致TValue
仅用于输出,则该泛型参数可能是协变的。@Servy绝对正确!我在回答中提到了你的评论。还要注意,为了使IReadOnlyList
在T
中是协变的,他们必须省略int IndexOf(T项)方法代码>以其他方式出现在列表界面中。@仔细考虑后,我意识到您经常使用IReadOnlyDictionary
来执行foreach
。这里有一个GetEnumerator
方法,其返回类型对于方差也很重要。为了让foreach
发挥作用,他们需要引入一些IReadOnlyKeyValuePair
或类似的东西。
Dictionary<object, object> dict = new Dictionary<string, string>();
dict["hello"] = new SomeOtherObject();
var dict=new Dictionary<int,string>();
DoSomething(dict);
DoSomething(Dictionary<object, object> dict)
{
var now=DateTime.Now;
dict[now]=now;
}