Gar*_*ann 9 c# types covariance contravariance variance
方差有效性的精确规则有点模糊,不具体.我将列出关于什么使类型有效 - 协变的规则,并将一些查询和个人注释附加到每个规则.
A型是有效的协变,如果它是:
1)指针类型或非泛型类型.
指针和非泛型类型在C#中不是变体,除了数组和非泛型委托.通用类,结构和枚举是不变的.我在这儿吗?
2)数组类型T [],其中T是共同有效的.
所以这意味着如果T数组的元素类型T[]是协变的(引用或数组元素类型),那么数组是协变的,如果元素类型是不变的(值类型),那么数组类型是不变的.数组在C#中不能逆变.我在这儿吗?
3)泛型类型参数类型,如果它未被声明为逆变.
我们通常说泛型类型在参数类型上是变体,但是参数类型在它自己的变量上.这是另一种简短形式吗?例如,泛型类型T<out D>是协变的D(因此协变有效),因此我们可以说类型参数D是协变有效的.我对吗?
4)构造的类,结构,枚举,接口或委托类型X可能是协同有效的.为了确定它是否,我们以不同方式检查每个类型参数,具体取决于相应的类型参数是声明为covariant(out),contravariant(in)还是invariant(both).(当然,类和结构的泛型类型参数永远不会被声明为'out'或'in';它们将始终是不变的.)如果第i个类型参数被声明为covariant,那么Ti必须是covariantly有效的.如果它被宣布为逆变,那么Ti必须是有效的.如果它被声明为不变量,则Ti必须是不变的有效.
最后一条规则,从上到下,完全不明确.
我们是否在讨论泛型类型的所有in/out/invariant类型参数的方差?根据定义,泛型类型一次可以是一种类型参数的协变/逆变/不变量.为了协变或不变,在这种情况下,立即对它的所有类型参数都没有任何意义.这意味着什么?
向前进.为了确定泛型类型是否具有协变有效性,我们检查其类型参数(而不是类型参数).因此,如果相应的类型参数是covariant/contravariant/invariant,那么type参数分别是covariantly/contravariantly/invariantly有效...
我需要更深入地解释这条规则.
编辑:谢谢埃里克.非常感激!
我完全理解有效/无差异/不变的有效意义.如果类型绝对不是逆变的,那么类型是有效的,这意味着它可以是不变的.完全没问题!
对于第4条规则,您将遵循如何确定构造的泛型类型是否在协规中有效的过程,如规则中所定义.但是,如何确定声明为covariant(out)的类型参数是否具有协变有效性?
例如,在通用接口I {...}的闭合构造接口I {}中,不应该在通用接口声明中将类型参数声明为协变类型参数(out U)这一事实意味着类型参数对象是协变的吗?我认为应该.Cuz这就是协变的定义.object
另外,第二条规则:
2)数组类型T [],其中T是共同有效的.
什么是数组元素类型T是有效的协变意味着什么呢?你的意思是元素类型是值类型(在这种情况下是不变的)或引用类型(在这种情况下是协变)?
Cuz投影T→ T[]只有T参考类型才是变体.
Eri*_*ert 13
你是对的,最后一条规则是最难理解的,但我保证你并不含糊.
一两个例子会有所帮助.考虑这种类型声明:
interface I<in T, out U, V> { ... }
Run Code Online (Sandbox Code Playgroud)
这种类型是否有协同作用?
I<string, object, int> { }
Run Code Online (Sandbox Code Playgroud)
让我们来看看我们的定义.
为了确定它是否,我们以不同方式检查每个类型参数,具体取决于相应的类型参数是声明为covariant(out),contravariant(in)还是invariant(both).
好的,所以类型参数是string,object和int.对应的参数是in T,out U和V分别.
如果第i个类型参数被声明为covariant(
out),那么Ti必须是covariantly有效的.
第二个类型参数是out U,因此object必须是协同有效的.它是.
如果它被声明为contravariant(
in),那么Ti必须是有效的.
第一个被宣布in T,因此string必须是有效的.它是.
如果它被声明为不变量,则Ti必须是不变的有效.
第三个V是不变的,所以int必须是不变的; 它必须是有效的,不一致的和共生的.它是.
我们通过了所有三项检查; 该类型I<string, object, int>是协同有效的.
好的,那个很容易.
现在让我们看看更难的一个.
interface IEnumerable<out W> { ... }
interface I<in T, out U, V>
{
IEnumerable<T> M();
}
Run Code Online (Sandbox Code Playgroud)
IEnumerable<T>里面I是一种类型.是IEnumerable<T>作为内部使用的I有效协变?
让我们来看看我们的定义.我们有类型参数T对应的类型参数out W.请注意,T是一个类型参数的I和类型参数的IEnumerable.
如果第i个类型参数(
W)被声明为covariant(out),那么Ti(T)必须是covariantly有效.
OK,所以IEnumerable<T>在I是有效的协变,T必须是有效的协变.是吗?没有.T被宣布为in T.声明的类型参数in永远不会协变有效.因此,IEnumerable<T>内部使用的类型I无法协同有效,因为违反了"必须"条件.
再次,就像我在回答你之前的问题时所说的那样,如果"有效的共生"和"有效的逆转"会给你带来悲伤,那就给它们不同的名字吧.它们是明确定义的正式属性; 如果它让你更容易理解,你可以给他们任何你想要的东西.