该方差的有效性确切规则有点含糊,不具体。 我将列出什么使一个有效的类型,协变的规则,并附加一些查询和个人注解每个这些规则。
A型是有效的协变 ,如果它是:
1)一个指针类型,或一个非通用的类型。
指针和非泛型类型在C#变种,除阵列和非泛型委托。 通用类,结构和枚举是不变的。 我说得对吗?
2)一种阵列型T []其中T是有效的协变。
因此,这意味着,如果元素类型T
阵列T[]
是协变(参考或数组元素类型),则该数组是协变,并且如果元素类型是不变的(值类型),则数组的类型是不变的。 数组不能在C#中被逆变。 我说得对吗?
3)一种一般类型参数类型,如果它没有声明为逆变。
我们常说,一个泛型类型是变种的参数类型,但对于一个参数类型是它自己的变体。 这是说,另一种缩写形式? 例如,通用型T<out D>
是协变D
(因此协变有效),因此我们可以说,类型参数D
是协变有效。 我对吗?
4)构建类,结构枚举,接口或委托类型X可能是有效的协变。 要确定它是否是,我们检查每个类型参数不同,这取决于相应的类型参数是否被宣布为协变(出),逆变(中),或不变(没有)。 (当然的类和结构的泛型参数永远不会被“在”声明“出来”否则,他们将永远是不变的。)如果第i个类型参数被宣布为协变,那么钛必须是有效的协变。 如果它被宣布为逆变,然后钛必须是有效的contravariantly。 如果它被宣布为不变量,然后钛必须有效目不暇接。
这最后一条规则,从上到下,是完全不明确。
我们是在谈论一个通用型的所有的输入/输出/不变的类型参数的变化? 根据定义,一个通用的类型可以是协变/逆变/上一次一个类型放慢参数是不变的。 要协变或不变,在这种情况下,它的所有的类型参数在一次不抱任何意义。 那会是什么意思呢?
向前进。 要确定是否泛型类型是协变有效,我们审视它的类型参数(不键入paramters)。 因此,如果对应的类型参数是协变/逆变/不变,那么类型参数协变/ contravariantly /分别目不暇接,有效...
我需要这条规则在更深入地解释。
编辑:感谢埃里克。 非常感激!
我不完全理解什么有效的协变/ contravariantly /目不暇接的意思。 A型有效covriantly,如果它绝对不是逆变,这意味着它可以是不变的。 完全没有!
对于第4个规则,你跟着如何确定一个构造的泛型类型是否是有效的协变,如在规则中定义的过程。 但是,你如何确定是否属于声明为协变(出)类型参数是协变有效?
例如,在封闭构造接口I {} 通用接口I {...}的, 应该不是张女士的类型参数object
被声明为协变类型参数(出U)在通用接口声明的意思该类型参数对象协变? 我认为它应该。 的Cuz这就是被协变的非常清晰。
此外,第二条规则:
2)一种阵列型T []其中T是有效的协变。
什么是数组元素类型T
是有效的协变意味着什么呢? 你的意思是元素类型是值类型 (不变在这种情况下)或(在这种情况下,协变)的引用类型?
曲子投影T
→ T[]
是唯一变体,如果T
是引用类型。
你是正确的,最后一条规则是最难理解,但我向你保证,这一点也不含糊。
一两个例子会有所帮助。 考虑这个类型声明:
interface I<in T, out U, V> { ... }
这类型的协变有效吗?
I<string, object, int> { }
让我们通过我们的定义。
要确定它是否是,我们检查每个类型参数不同,这取决于相应的类型参数是否被宣布为协变(出),逆变(中),或不变(没有)。
OK,所以类型参数是string
, object
和int
。 相应的参数是in T
, out U
和V
分别。
如果第i个类型参数被宣布为协变( out
),然后钛必须是有效的协变。
第二种类型的参数是out U
,所以object
必须是有效的协变。 它是。
如果它被宣布为逆变( in
),然后钛必须是有效的contravariantly。
第一个被宣布in T
,这样string
必须是有效的contravariantly。 它是。
如果它被宣布为不变量,然后钛必须有效目不暇接。
第三V
是不变的,所以int
必须有效目不暇接; 它必须是有效的contravariantly和协变两者。 它是。
我们通过所有三项检查; 类型I<string, object, int>
是有效的协变。
好了,这一个很容易。
现在,让我们来看看一个更难的。
interface IEnumerable<out W> { ... }
interface I<in T, out U, V>
{
IEnumerable<T> M();
}
IEnumerable<T>
内I
是一种类型。 是IEnumerable<T>
作为内部使用I
有效的协变?
让我们通过我们的定义。 我们有类型参数T
对应类型参数out W
。 需要注意的是T
是一个类型参数 I
和类型参数 IEnumerable
。
如果第i个类型参数( W
)被宣布为协变( out
),然后钛( T
)必须是有效的协变。
好了,为IEnumerable<T>
在I
是有效的协变, T
必须是有效的协变。 是吗? 没有。 T
被宣布为in T
。 被声明的类型参数in
从来都不是有效的协变。 因此,类型IEnumerable<T>
作为内部使用的I
是无效的协变,这是因为“必须”条件被破坏。
同样,像我在回答你刚才的问题说,如果“有效的协变”和“有效contravariantly”是给你的悲伤,只是给他们不同的名字。 他们明确的正规性; 你可以给他们打电话,你想,如果它使你更容易去了解任何东西。
不,你的注释是搞砸了。
这篇文章是真的很难理解,部分原因是“有效的协变”有什么都没有做协方差。 埃里克不指出这一点,但它意味着,每一句话你要“unthink”自然的含义,然后想在“协变有效”这些奇怪的定义而言,“有效contravariantly”和“有效目不暇接”。
我强烈建议你,而不是阅读的里氏替换原则,再想想可替代性。 当从LSP角度望去协方差,逆变和不变性有非常简单的定义。
然后,您可能会注意到在编译时的C#规则并不完全与LSP匹配(遗憾的是 - 这主要是在Java中取得并复制到C#来帮助法院Java程序员错误)。 在另一方面,在运行时LSP规则必须遵守,所以如果你开始与这些,你会写代码,无论编译和运行正确,我认为这是一个更有价值的努力比学习C#语言的规则(除你正在写一个C#编译器)。
你怎么确定是否属于声明为协变(出)类型参数是协变有效?
阅读规则3。
在闭合构造接口I{string, object int>
通用接口的I<in T, out U, V>
应该不是非常事实,即类型参数object
被声明为协变型参数out U
在通用接口声明意味着该类型参数object
是协变的?
首先,你使用的“协变”,你的意思是“协变合法”。 请记住,这是不同的东西。
其次,让我们再经历一遍。 为object
协变有效吗? 是的,规则1是I<string, object, int>
协变有效吗? 是的,规则3,其中指出:
- 对应于T中的类型参数必须是contravariantly有效。
- 与U对应的类型参数必须是协变有效。
- 对应到V的类型参数必须是这两者。
由于所有这三个条件都满足, I<string, object, int>
是协变有效。
在“数组类型T [],其中T是有效的协变”是什么的数组元素类型T是有效的协变意思?
我不明白的问题。 我们定义什么是“协变有效”的意思。 第2条是“协变有效”定义的一部分。
作为一个例子,是object[]
协变有效? 是的,因为object
是协变有效。 如果我们有:
interface IFoo<out T> { T[] M(); }
是T[]
协变有效吗? 是的,因为T
是协变有效。
如果我们有
interface IBar<in T> { T[] M(); }
是T[]
协变有效吗? 号对于数组类型为协变有效元素类型必须是协变有效,但T
不是。