C# 中的方差规则

2024-01-06

The 方差有效性的精确规则 http://blogs.msdn.com/b/ericlippert/archive/2009/12/03/exact-rules-for-variance-validity.aspx有点模糊而且不具体。我将列出使类型有效协变的规则,并将一些查询和个人注释附加到每个规则。

一个类型是有效协变如果是:

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

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

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

所以这意味着如果元素类型T一个数组的T[]是协变的(引用或数组元素类型),那么数组就是协变的,如果元素类型是不变的(值类型),那么Array类型就是不变的。 C# 中的数组不能逆变。我在这儿吗?

3) 泛型类型参数类型(如果未将其声明为逆变)。

我们通常说泛型类型是参数类型的变体,但参数类型本身就是变体。这是这句话的另一种缩写形式吗?例如,泛型类型T<out D>是协变的D(因此协变有效),因此我们可以说类型参数D是协变有效的。我对吗?

4) 构造类、结构、枚举、接口或委托类型 X 可能是有效的协变。为了确定是否是,我们以不同的方式检查每个类型参数,具体取决于相应的类型参数是否被声明为协变(out)、逆变(in)或不变(两者都不是)。 (当然,类和结构的泛型类型参数永远不会被声明为“out”或“in”;它们始终是不变的。)如果第 i 个类型参数被声明为协变,则 Ti 必须是有效的协变。如果它被声明为逆变,那么 Ti 必须是逆变有效的。如果它被声明为不变式,那么 Ti 必定是有效的不变式。

最后一条规则,从上到下,完全是模棱两可的。

我们是在谈论泛型类型在其所有输入/输出/不变类型参数上的差异吗?根据定义,泛型类型一次可以对一个类型参数进行协变/逆变/不变。在这种情况下,对于所有类型参数来说,协变或不变没有任何意义。这意味着什么?

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

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


编辑:谢谢埃里克。不胜感激!

我完全理解有效的协变/逆变/不变的含义。如果类型绝对不是逆变的,则它是协变有效的,这意味着它可以是不变的。完全没问题!

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

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

另外,第二条规则:

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

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

因为投影TT[]是唯一的变体,如果T是引用类型。


你说得对,最后一条规则是最难理解的,但我向你保证它并不含糊。

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

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

是这个类型吗协变有效?

I<string, object, int> { }

让我们看一下我们的定义。

为了确定是否是,我们以不同的方式检查每个类型参数,具体取决于相应的类型参数是否被声明为协变(out)、逆变(in)或不变(两者都不是)。

好的,所以类型参数是string, object and int。对应的参数为in T, out U and V, 分别。

如果第 i 个类型参数被声明为协变 (out),那么它必须是协变有效的。

第二个类型参数是out U, so object必须是协变有效的。这是。

如果它被声明为逆变(in),那么 Ti 必定是逆变有效的。

第一个被宣布了in T, so string必须是逆变有效的。这是。

如果它被声明为不变式,那么 Ti 必定是有效的不变式。

第三V是不变的,所以int必须是不变有效的;它必须同时有效逆变和协变。这是。

我们通过了所有三项检查;方式I<string, object, int>是协变有效的。

好吧,那很简单。

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

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

IEnumerable<T> inside I是一种类型。是IEnumerable<T>正如里面所使用的I协变有效?

让我们看一下我们的定义。我们有类型参数T对应类型参数out W。注意T是一种类型范围 of I和一个类型argument of IEnumerable.

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

好的,所以对于IEnumerable<T> in I协变有效,T必须是协变有效的。是吗?不。T被宣布为in T。声明的类型参数in永远不会是协变有效的。因此类型IEnumerable<T>正如里面所使用的I协变无效,因为违反了“必须”条件。

再说一遍,就像我在回答你之前的问题时所说的那样,如果“有效协变”和“有效逆变”让你感到悲伤,只需给它们起不同的名字即可。它们是明确定义的形式属性;如果您更容易理解,您可以随意称呼它们。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 中的方差规则 的相关文章

随机推荐

  • mysql 分区

    只是想验证数据库分区仅在数据库级别实现 当我们查询分区表时 我们仍然执行正常查询 我们的查询没有什么特别的 解析查询时会自动执行优化 对吗 例如我们有一个名为 地址 的表 其中有一列名为 国家 地区代码 和 城市 所以如果我想获得美国纽约的
  • 如何创建 RSS 提要并显示它?

    在我为广播电台维护的网站上 他们有一个显示新闻文章的页面 现在新闻发布在一个 html 页面中 然后由包含所有导航的 php 页面读取 我被要求将其制作成 RSS 源 我该怎么做呢 我知道如何制作 XML 文件 但编辑新闻文件的人缺乏技术
  • 避免在 Android 上尝试/捕获

    我是 Android 环境的新手 我已经开始编写一些代码来对数据库执行一些查询 当我必须处理异常时 我不知道正确的方法是什么 我曾经使用过 Androidthrows方法声明 但似乎throws安卓不允许吗 只是try catch 我这样说
  • 使用 VBA 以编程方式安装 Microsoft Access 加载项

    查找有关 Microsoft Access 加载项开发的信息就像拔掉所有牙齿一样 是的 我发现了几篇托管加载项文章 但几乎找不到非托管加载项的内容 我确实找到了一篇很棒的文章 它在创建基本上是一个非托管的 mda 项目方面非常古老 我已经遵
  • PIP 在 Windows 8 上的哪里存储/保存 Python 3 模块/包?

    我到处都找过了 但找不到软件包的安装位置 此外 包裹是来自pip questions tagged pip 模块 库或只是包python questions tagged python术语 使用此命令列出全局包及其位置 pip list v
  • Gradle 获得“sudo”权限

    我有下一个问题 我需要使用 Gradle 在服务器上执行一些部署内容 但为此 Gradle 应该在目标部署服务器上具有 root 访问权限 我有 sudo 的密码 但我不知道如何将其插入服务器 有没有办法从 Gradle 任务中获得 sud
  • 注释属性必须是类文字吗?为什么?常量也应该没问题

    有人可以解释为什么字符串和类注释参数的预期不同吗 为什么编译器需要类的文字 同时也接受字符串的常量 使用 Spring 的 RequestMapping 的工作示例 public class MyController public stat
  • UIView 动画后 UIView 内的 UIButton 不起作用

    我在这个论坛上看到了很多问题 这些问题给出了这个主题 UIButton inside a UIView when animated does not work 的答案 但是在尝试了类似的答案之后 a UIViewAnimationOptio
  • R 中的函数工厂

    我尝试通过返回专门函数的字典来提出一个函数工厂 或多或少类似于函数式编程风格 我尝试在下面的代码中执行此操作 require hash names c aa bb cc funs hash for i in seq length names
  • PHP 中 ::(双冒号)和 ->(箭头)有什么区别?

    PHP 中有两种不同的方法来访问方法 但是有什么区别呢 response gt setParameter foo bar and sfConfig set foo bar 我假设 gt 带有大于号或 V 形的破折号 用于变量函数 并且 双冒
  • 将 this 传递给函数的基本查询

    我正在尝试更好地理解 JavaScript function foo console log this normal function call foo this will refer to window 当我尝试将其传递给函数时 它会抛出
  • 如何判断这个内存泄漏是从哪里来的呢?

    如何确定代码中的内存泄漏来自何处 除了我的应用程序中的 main 函数之外 它没有引用任何内容 看来您正在尝试同时使用 NSZombieEnabled 和泄漏 这两种诊断技术不能一起工作 NSZombieEnabled 使所有已释放的对象都
  • 我应该如何在 Perl 中序列化代码引用?

    我希望nstore一个 Perl 哈希值 其中还包含代码引用 按照此perldoc http perldoc perl org Storable html CODE REFERENCEShttp perldoc perl org Stora
  • 为什么二叉搜索树中的查找时间复杂度为 O(log(n))?

    我可以看到 当在 a 中查找值时 如何BST每次将节点与我们要查找的值进行比较时 我们都会留下一半的树 但是我不明白为什么时间复杂度是O log n 所以 我的问题是 如果我们有一个包含 N 个元素的树 为什么查找树并检查特定值是否存在的时
  • 从 PHP 文本中提取 URL

    我有这样的文字 string this is my friend s website http example com I think it is coll 如何将链接提取到另一个变量中 我知道应该特别使用正则表达式preg match 但
  • .NET System.IO.BinaryWriter 写入的原始字节是否可以被其他平台读取?

    背景 我正在手动将大数据块写入二进制文件System IO BinaryWriter 我之所以选择这种方法 是因为与各种其他序列化和反序列化方法相比 它的性能得到了提高 我目前正在使用System IO BinaryReader Quest
  • 如何在 VS Code 中调试 vue js 应用程序?

    我使用创建了新的 vue js 应用程序vue init webpack my test3 在 VS Code v1 7 1 中 我尝试调试此应用程序和默认值launch json程序设置为 configurations type node
  • 如何处理nginx反向代理https到http方案重定向

    我已经将 nginx 设置为托管 jenkins 和其他一些应用程序的 ubuntu 实例上的反向代理 我使用 nginx 根据相对路径路由到各种应用程序 从客户端到 nginx 的所有流量都通过 https 进行 在防火墙后面 nginx
  • 在lisp中如何定义这样的常量?

    在Python中可以做到这一点 EMPTY PAWN KNIGHT BISHOP ROOK QUEEN KING BPAWN range 8 你会如何在 lisp 中做等价的事情 在 Lisp 中 只使用符号会更惯用 通常作为自评估关键字符
  • C# 中的方差规则

    The 方差有效性的精确规则 http blogs msdn com b ericlippert archive 2009 12 03 exact rules for variance validity aspx有点模糊而且不具体 我将列出