首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C#中的方差规则

C#中的方差规则
EN

Stack Overflow用户
提问于 2013-04-26 22:43:38
回答 3查看 1.2K关注 0票数 10

方差有效性的精确规则有点模糊,不太具体。我将列出使类型有效的规则,并在每个规则上附加一些查询和个人注释。

一个类型是有效的,如果它是

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

指针和非泛型类型在C#中不变体,但数组和非泛型委托除外.泛型类、结构和枚举是不变的。我就在这儿吗?

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

这意味着,如果数组的元素类型T是协变量(引用或数组元素类型),那么数组是协变量的,如果元素类型是不变的(值类型),那么数组类型是不变的。数组在C#中不能是反变体。我就在这儿吗?

( 3)泛型类型参数类型(如果未声明为反变体)。

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

4)构造的类、结构、枚举、接口或委托类型X可能是共同有效的。为了确定是否是,我们根据对应的类型参数是否声明为协变量(out)、反变量(in)或不变量(都不声明),对每个类型参数进行不同的检查。(当然,类和结构的泛型类型参数永远不会被声明为“out”或“in”;它们总是不变的。)如果ith类型参数声明为协变量,则Ti必须是有效的协变量。如果它被宣布为反变体,则Ti必须是有效的。如果它被声明为不变量,则Ti必须是有效不变的。

的最后一条规则,自上而下,都是非常模糊的。

我们讨论的是泛型类型对其所有输入/输出/不变类型参数的方差吗?根据定义,泛型类型可以是一次在一种类型参数上的协变/反变/不变量。在这种情况下,要成为协变量或不变量,它的类型参数一次就不具有任何意义。这可能意味着什么?

向前看。为了确定泛型类型是否具有协变量有效性,我们将检查它的类型参数(非类型参数)。因此,如果对应的类型参数是协变/逆变/不变量,则类型参数分别是有效的协变量/逆变/不变的。

我需要更深入地解释这个规则。

编辑:谢谢,埃里克。非常感谢!

我完全理解什么是有效的,共变的/反差的/不变的。一个类型是有效的,如果它绝对不是反变体,这意味着它可以是不变的。完全没问题!

对于第4条规则,按照规则中的定义,遵循如何确定构造的泛型类型是否是有效的过程。但是,如何确定声明为协变量(out)的类型参数是否具有协变量的有效性?

例如,在泛型接口I{. }的封闭构造接口I{}中,不应该将类型参数object声明为协变类型参数(Out),这意味着类型参数对象是协变的吗?我觉得应该。因为这就是协变的定义。

此外,第二条规则:

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

数组元素类型T 是有效的是什么意思?您的意思是元素类型是值类型(在本例中是不变的)还是引用类型(在本例中是协变的)?

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-27 00:31:00

你说得对,最后一条规则是最难理解的,但我向你保证,它并非模棱两可。

一两个例子会有帮助。请考虑以下类型声明:

代码语言:javascript
运行
复制
interface I<in T, out U, V> { ... }

此类型是否具有协变量有效性?

代码语言:javascript
运行
复制
I<string, object, int> { }

让我们来看看我们的定义。

为了确定是否是,我们根据对应的类型参数是否声明为协变量(out)、反变量(in)或不变量(都不声明),对每个类型参数进行不同的检查。

好的,所以类型参数是stringobjectint。相应的参数分别为in Tout UV

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

第二个类型的参数是out U,所以object必须是有效的。它是。

如果它被宣布为反变异体(in),则Ti必须是有效的。

第一个被声明为in T,因此string必须是有效的。它是。

如果它被声明为不变量,则Ti必须是有效不变的。

第三种V是不变量的,所以int必须是不变的,所以它必须是有效的,既可以是对比的,也可以是共变的。它是。

我们通过了所有三个检查;类型I<string, object, int>是有效的。

好吧,那个很简单。

现在让我们来看看一个更难的问题。

代码语言:javascript
运行
复制
interface IEnumerable<out W> { ... }
interface I<in T, out U, V> 
{
    IEnumerable<T> M();
}

IEnumerable<T> is I是一种类型。IEnumerable<T>I中的使用是否有效?

让我们来看看我们的定义。类型参数T对应于类型参数out W。注意,TI的类型参数和IEnumerable的类型参数。

如果ith类型参数(W)声明为协变量(out),则Ti (T)必须是有效的协变量。

好的,如果IEnumerable<T>I中是有效的,那么T必须是有效的。是吗?不是的。T被宣布为in T。声明为in的类型参数从不会以协变方式有效。因此,在IEnumerable<T>中使用的I类型是无效的,因为违反了“必须”条件。

再一次,就像我在回答你之前的问题时说的,如果“有效共变”和“有效对比”会给你带来悲伤,那就给他们起不同的名字吧。它们是定义良好的正式属性;如果它使您更容易理解,您可以将它们称为任意类型的属性。

票数 13
EN

Stack Overflow用户

发布于 2013-04-26 23:53:40

不,你的注解搞砸了。

这篇文章真的很难理解,部分原因是“有效的协变量”与协方差毫无关系。Eric确实指出了这一点,但它意味着对于每句话,你都必须“不去思考”自然的含义,然后用这些奇怪的定义来思考“有效共变”、“有效对比”和“有效不变”。

我强烈建议您阅读Liskov替换原则,然后考虑可替换性。从LSP的角度来看,协方差、反方差和不变性有着非常简单的定义。

然后,您可能会注意到,编译时的C#规则与LSP不完全匹配(不幸的是,这主要是在C#中犯的错误,并被复制到C#中以帮助讨好Java程序员)。另一方面,在运行时必须遵循LSP规则,因此如果您从这些规则开始,您将编写编译和正确运行的代码,我认为这比学习C#语言规则更有价值(除非您正在编写C#编译器)。

票数 4
EN

Stack Overflow用户

发布于 2013-04-27 06:44:52

如何确定声明为协变量(out)的类型参数是否具有协变量有效性?

读第3条。

在泛型接口I{string, object int>封闭构造接口 I<in T, out U, V>中,类型参数object在泛型接口声明中声明为协变类型参数out U这一事实不就意味着类型参数object是协变的吗?

首先,您使用的是“协变量”,意思是“共同有效”。记住,这些是不同的东西。

第二,让我们再看一遍。object是否共同有效?是的,根据规则1. I<string, object, int>是否共同有效?是的,第3条规定:

  • 与T对应的类型参数必须是相反有效的。
  • 与U对应的类型参数必须是协变量有效的。
  • 与V对应的类型参数必须为两者。

由于满足了所有三个条件,所以I<string, object, int>是共同有效的。

在“数组类型T[],其中T是有效的协变”中,数组元素类型T是有效的协变量意味着什么?

我不明白这个问题。我们正在定义“共同有效”的含义。第2条是“共同有效”定义的一部分。

例如,object[]是否是共同有效的?是的,因为object是共同有效的。如果我们有:

代码语言:javascript
运行
复制
interface IFoo<out T> { T[] M(); }

T[]是否共同有效?是的,因为T是共同有效的。

如果我们有

代码语言:javascript
运行
复制
interface IBar<in T> { T[] M(); }

T[]是否共同有效?不是的。若要使数组类型具有协变量有效性,则其元素类型必须是协变量有效的,但T无效。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16246281

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档