C#中的方差规则 [英] Variance rules in C#

查看:110
本文介绍了C#中的方差规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

精确方差有效性的规则有点含糊且不具体。我将列出使类型有效-协变的规则,并向每个规则附加一些查询和个人注释。

The Exact rules for variance validity are a bit vague and not specific. I'm going to list the rules for what makes a type valid-covariantly, and attach some queries and personal annotations to each of those rules.

类型为协变量有效,如果它是:


1)指针类型或非泛型类型。

1) a pointer type, or a non-generic type.

指针和非通用类型在C#中不是变量,除了数组和非通用委托。泛型类,结构和枚举是不变的。我在这里吗?

Pointers and non-generic types are not variant in C#, except for arrays and non-generic delegates. Generic classes, structs and enums are invariant. Am I right here?


2)数组类型T [],其中T是协变有效的。

2) An array type T[] where T is valid covariantly.

因此,这意味着如果数组<$的元素类型 T c $ c> T [] 是协变的(引用或数组元素类型),则数组是协变的;如果元素类型是不变的(值类型),则Array类型是不变的。数组在C#中不能是互变的。我在这里吗?

So this means that if the element type T of an array T[] is covariant (reference or array element type), then the array is covariant, and if the element type is invariant (value type), then the Array type is invariant. Arrays cannot be contravariant in C#. Am I right here?


3)泛型类型参数类型,如果没有声明为协变的话。

3) A generic type parameter type, if it was not declared as being contravariant.

我们通常说泛型是参数类型的变体,但参数类型本身是变体。这是另一种简短的说法吗?例如,通用类型 T< out D> D 上是协变的(因此协变有效),因此我们可以说类型参数 D 是协变有效的。我对吗?

We normally say that a generic type is variant on a parameter type, but for a parameter type to be variant on it's own. Is this another short form for saying that? for example, the generic type T<out D> is covariant on D (hence covariantly valid), hence we can say that the type parameter D is covariantly valid. Am I right?


4)构造的类,结构,枚举,接口或委托类型X可能是协变有效的。为了确定是否为实,我们根据对应的类型参数是声明为协变(out),相反(in)还是不变(都不)来不同地检查每个类型参数。 (当然,类和结构的泛型类型参数永远不会声明为 out或 in;它们始终是不变的。)如果第i个类型参数声明为协变,则Ti必须协变有效。如果声明为反变量,则Ti必须反有效。如果声明为不变,则Ti必须不变。

4) A constructed class, struct, enum, interface or delegate type X might be valid covariantly. To determine if it is, we examine each type argument differently, depending on whether the corresponding type parameter was declared as covariant (out), contravariant (in), or invariant (neither). (Of course the generic type parameters of classes and structs will never be declared 'out' or 'in'; they will always be invariant.) If the ith type parameter was declared as covariant, then Ti must be valid covariantly. If it was declared as contravariant, then Ti must be valid contravariantly. If it was declared as invariant, then Ti must be valid invariantly.

最后一条规则从上到下完全不明确。

我们是否在谈论泛型类型在其所有输入/输出/不变类型参数上的差异?根据定义,泛型类型一次可以在一个类型参数上是协变/逆变/不变的。无论是协变还是不变,在这种情况下,一次所有类型参数都不具有任何意义。那是什么意思?

Are we talking about a generic type's variance on all of its in/out/invariant type parameters? By definition, A generic type can be covariant/contravariant/invariant on one type paramter at a time. To be covariant or invariant, in this case, on all of it's type parameters at once doesn't hold any meaning. What could that mean?

向前迈进。为了确定泛型类型是否协变有效,我们检查其类型参数(不是类型参数)。因此,如果相应的类型参数是协变/相反/不变的,则类型参数分别是协变/相反/不变的……

Moving forward. To determine if the generic type is covariantly valid, we examine its type arguments (not type paramters). So if the corresponding type parameter is covariant/contravariant/invariant, then the type argument is valid covariantly/contravariantly/invariantly respectively ...

我需要对此规则进行解释更深入。

I need this rule be explained in more depth.

编辑:谢谢Eric。非常感谢!

Thanks Eric. Greatly appreciated!

我确实完全理解协变/反变/不变的有效含义。如果类型绝对不是协变的,则类型是有效的,这意味着它可以是不变的。

I do perfectly understand what valid covariantly/contravariantly/invariantly mean. A type is valid covriantly, if it's definitely not contravariant, which means that it can be invariant. perfectly fine!

对于第四条规则,您将按照规则确定如何确定构造的泛型类型是否有效协变的过程。但是,您如何确定声明为协变(出)的类型参数是否协变有效?

For the 4th rule, you follow the procedure of how to determine whether a constructed generic type is valid covariantly, as defined in the rule. But, how do you determine if a type argument that's declared as covariant (out) is covariantly valid?

例如,在通用接口I {...} 封闭构造接口I {} 中,不是应该将类型参数 object 声明为协变类型参数(输出U)在通用接口声明中意味着类型实参对象是协变的?我认为应该。因为这就是协变的定义。

For example, in the closed constructed interface I { } of the generic interface I { ... }, shouldn't the very fact that the type argument object is declared as a covariant type parameter(out U) in the generic interface declaration mean that the type argument object is covariant? I think it should. Cuz that's the very definition of being covariant.

第二条规则:


2)数组类型T [ ],其中T是协变有效的。

2) An array type T[] where T is valid covariantly.

数组元素类型 T 是协变量有效的是什么是什么意思?您是说元素类型是值类型(在这种情况下为不变)还是在引用类型(在这种情况下为协变)?

What does the array element type T being valid covariantly mean? Do you mean the element type being a value type (invariant in this case) or a reference type (covariant in this case)?

因为投影 T T [] 仅当 T 是引用类型时才是变体。

Cuz the projection TT[] is only variant if T is reference type.

推荐答案

您是对的,最后一条规则是最难理解的规则,但我向您保证,它不是模棱两可的。

You are right that the last rule is the hardest one to understand but I assure you it is not ambiguous.

一个或两个示例会有所帮助。考虑以下类型声明:

An example or two will help. Consider this type declaration:

interface I<in T, out U, V> { ... }

此类型协变有效吗?

I<string, object, int> { }

让我们仔细看看我们的定义。

Let's go through our definition.

要确定是否存在,我们根据对应的类型参数被声明为协变(out),逆变(in)还是不变(都不)来不同地检查每个类型实参。

To determine if it is, we examine each type argument differently, depending on whether the corresponding type parameter was declared as covariant (out), contravariant (in), or invariant (neither).

确定,因此类型参数为 string 对象 int 。相应的参数是 in T out U V

OK, so the type arguments are string, object and int. The corresponding parameters are in T, out U and V, respectively.


如果将ith类型参数声明为协变( out ) ,则Ti必须协变有效。

If the ith type parameter was declared as covariant (out), then Ti must be valid covariantly.

第二个类型参数是 out U ,因此 object 必须协变量有效。

The second type parameter is out U, so object must be valid covariantly. It is.


如果它被声明为变数( in ),则Ti必须是反有效的。

If it was declared as contravariant (in), then Ti must be valid contravariantly.

第一个在T中被声明为 ,所以 string 必须相反地有效。

The first was declared in T, so string must be valid contravariantly. It is.


如果声明为不变,则Ti必须不变。

If it was declared as invariant, then Ti must be valid invariantly.

第三个 V 是不变的,因此 int 必须不变;它必须是反变和协变有效的。

The third V was invariant, so int must be valid invariantly; it must be both valid contravariantly and covariantly. It is.

我们通过了所有三张支票;类型 I< string,object,int> 是协变量有效的。

We pass all three checks; the type I<string, object, int> is valid covariantly.

好,那很容易。

现在让我们来看一个更难的东西。

Now let's look at a harder one.

interface IEnumerable<out W> { ... }
interface I<in T, out U, V> 
{
    IEnumerable<T> M();
}

IEnumerable< T> I 内的是一种类型。 I 中使用的 IEnumerable< T> 是否协变量有效?

IEnumerable<T> inside I is a type. Is IEnumerable<T> as used inside I valid covariantly?

我们来定义一下。我们有类型参数 T 对应于类型参数 out W 。请注意, T I parameter 类型和 argument IEnumerable

Let's go through our definition. We have type argument T corresponding to type parameter out W. Note that T is a type parameter of I and a type argument of IEnumerable.


如果第i个类型参数( W )被声明为协变( out ),则Ti( T )必须协变有效。

If the ith type parameter (W) was declared as covariant (out), then Ti (T) must be valid covariantly.

好,所以对于 IEnumerable< T> > I 要协变有效, T 必须协变有效。是吗?没有。在T 中将 T 声明为。在$code>中声明为的类型参数永远不会协变有效。因此,在 I 中使用的类型 IEnumerable< T> 协变量无效,因为违反了必须条件

OK, so for IEnumerable<T> in I to be valid covariantly, T must be valid covariantly. Is it? NO. T was declared as in T. A type parameter that is declared in is never valid covariantly. Therefore the type IEnumerable<T> as used inside I is not valid covariantly, because the "must" condition is violated.

再次,就像我在回答上一个问题时所说的那样,如果协变量有效和变量有效给您带来悲伤,只需给他们起不同的名字即可。它们是定义明确的形式属性;如果您更容易理解,则可以将它们命名为任何您想要的名称。

Again, like I said in my answer to your previous question, if "valid covariantly" and "valid contravariantly" are giving you grief, just give them different names. They are well-defined formal properties; you can call them anything you want if it makes it easier for you to understand.

这篇关于C#中的方差规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆