为什么数组协方差被认为如此可怕?

2024-03-14

在 .NET 中,引用类型数组是协变的。这被认为是一个错误。但是,我不明白为什么这这么糟糕,请考虑以下代码:

string[] strings = new []{"Hey there"};
object[] objects = strings;
objects[0] = new object();

噢,这可以编译,但在运行时会失败。当我们试图将一个对象粘贴到 string[] 中时。好吧,我同意这很糟糕,但是 T[] 扩展了 Array 并且还实现了IList (and IList<T>,我想知道它是否实现了IList<BaseType>...>。 Array 和 IList 都让我们犯同样可怕的错误。

string[] strings = new []{"Hey there"};
Array objects = strings;
objects.SetValue(new object(),new[]{0});

列表版本

string[] strings = new []{"Hey there"};
IList objects = strings;
objects[0] = new object();

T[] 类由 CLR 生成,并且必须包含对等效项的类型检查set_Item方法(数组实际上没有方法)。

是否担心设置为 T[] 必须在运行时进行类型检查(这违反了您在编译时期望的类型安全)?当通过上面提供的方法有等效的方法搬起石头砸自己的脚时,为什么认为阵列表现出这种属性是有害的?


在 .NET 中,引用类型数组是协变的。这被认为是一个错误。

类型安全破坏数组协方差被认为是有些人这是 .NET 设计中的一个错误。并不是所有人都这么认为。我不认为这是一个mistake;我认为这是一个不幸的选择。所有设计过程都涉及在不受欢迎的替代方案之间进行选择。在这种情况下,需要选择是添加一个不安全的隐式转换(这会给所有数组写入带来运行时成本),还是构建一个无法轻松实现 Java 类型系统的类型系统。这是一个艰难的选择,类型系统的设计者利用他们所掌握的信息做出了最好的选择。

当然,这种解释只是在回避问题。那么Java的设计者不就犯了一个错误吗?可能是,也可能不是;很可能 Java 的设计者在设计类型系统时也面临着权衡。如果有任何了解 Java 类型系统发展历史的专家愿意在这里插话这些权衡是什么,我很想知道。

经过十年的事后诸葛亮,我个人更希望 .NET 类型系统的设计者选择避开破坏安全的数组协变。但这并不意味着这个选择是一个“错误”,它只是让它有些不幸。

是否担心设置为 T[] 必须在运行时进行类型检查(这违反了您在编译时期望的类型安全)?

是的。这意味着看起来应该总是成功运行的代码可能会在运行时失败。这意味着正确的代码会带来性能损失。

当通过上面提供的方法有等效的方法搬起石头砸自己的脚时,为什么认为阵列表现出这种属性是有害的?

这是一个奇怪的问题。问题本质上是“我已经有两把枪了,我可以用它们搬起石头砸自己的脚,那么为什么用第三把枪搬起石头砸自己的脚对我来说是有害的呢?”

两种违反类型安全的危险模式的存在并不会降低第三种模式的危险性。

当您绝对肯定地知道您所做的事情是安全的(即使编译器不知道)时,就会存在违反类型安全的语言和运行时功能。如果您不太了解这些功能而无法安全地使用它们,请不要使用它们。

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

为什么数组协方差被认为如此可怕? 的相关文章

  • asp.net c# 将数据集中的数据转换为电子邮件正文?

    从数据集到电子邮件正文的最佳方式是什么 我有一个 net 控制台应用程序 用于根据存储过程的结果发送电子邮件通知 并且想知道如何最好地从 SQL 数据转到电子邮件正文 带有颜色和字体的 html 正文是最好的 但纯文本也可以 thanks
  • 我们如何将数据从一个打开的表单传递到另一个打开的表单?

    winform中如何将数据从一个窗体传递到另一个打开的窗体 在 Windows 应用程序中 一个窗体打开另一个窗体 当我在父表单中输入一些数据时 这些数据将立即反映在另一个子表单中 这将如何发生 取决于你想要多花哨 最简单的方法就是直接调用
  • 如何“杀死”Pthread?

    我正在学习 Pthreads 并且想知道杀死这样一个对象的最佳方法是什么 在寻找类似的问题后 我无法找到 明确 的答案 但请随时向我指出任何相关问题 我正在使用一个小型客户端服务器应用程序 其中服务器主线程正在侦听套接字上的客户端连接 每次
  • 如何从 List 中的字符串中删除数字/数字?

    我有一个字符串列表 List
  • 使用 Selenium for C# 登录 Facebook

    我一直在使用 Selenium C 框架并尝试进行 facebook 登录 但没有任何运气 这是我到目前为止得到的 基于这篇文章 使用 Selenium 测试 Facebook Connect 应用程序 https stackoverflo
  • C++ 私有静态成员变量

    此 C 代码在编译时产生链接器错误 A h class A public static void f private static std vector
  • Azure 2012 年 10 月 SDK 损坏 UseDevelopmentStorage=true

    有人尝试过使用 usedevelopmentstorage true 连接字符串的 2012 年 10 月 Azure sdk 吗 CloudStorageAccount Parse UseDevelopmentStorage true 抛
  • C++ 中的 Java ArrayList [重复]

    这个问题在这里已经有答案了 在Java中我可以做 List
  • C 中“for”循环中的两个变量

    我正在编写一些代码 需要在其中使用两个变量for环形 下面的代码看起来没问题吗 它确实给了我预期的结果 for loop 1 offset loop 2 offset 2 loop 1 gt offset 190 loop 2 lt 190
  • 控制器中的异常处理 (ASP.NET MVC)

    当您自己的代码抛出异常并从控制器中的操作调用时 应该如何处理 我看到很多最佳实践的例子 其中根本没有 try catch 语句 例如 从存储库访问数据 public ViewResult Index IList
  • 如何防止字符串被截留

    我的理解 可能是错误的 是 在 C 中 当你创建一个字符串时 它会被实习到 实习生池 中 这保留了对字符串的引用 以便多个相同的字符串可以共享操作内存 但是 我正在处理很多很可能是唯一的字符串 一旦完成每个字符串 我需要将它们从操作内存中完
  • 替换 JSON 中的转义字符

    我想用空格替换 JSON 字符串中的 字符 我怎样才能做到这一点 我发现从 JSON 字符串中删除所有转义字符的最简单 最好的方法是将字符串传递到正则表达式 Unescape 方法 此方法返回一个没有转义字符的新字符串 甚至删除了 n t
  • 从窗口内容截取屏幕截图(无边框)

    我正在寻找有关如何使用 C 将表单内容保存在位图中的解决方案 我已经尝试过使用 DrawToBitmap 但它捕获了所有带边框的窗口 这就是这段代码的结果 public static Bitmap TakeDialogScreenshot
  • 套接字:监听积压并接受

    listen sock backlog 在我看来 参数backlog限制连接数量 这是我的测试代码 server initialize the sockaddr of server server sin family AF INET ser
  • 无法将方法组“Read”转换为非委托类型“bool”

    我正在尝试使用SqlDataReader检查条目是否存在 如果存在则返回ID 否则返回false 当我尝试编译时 出现错误 无法将方法组 Read 转换为非委托类型 bool 我一直在遵循在 VB 中找到的示例 但似乎翻译可能不正确 pri
  • System.diagnostics.process 进程在托管后无法在 IIS 上运行?

    我正在尝试从网络应用程序安装 exe 当我在本地运行应用程序 从 asp 开发服务器 时 它安装正确 但当我托管在 IIS 上时 它不起作用 我在asp net页面的Page load方法上编写了这段代码 想要在客户端计算机上安装Test
  • 需要使用 openssl 加密和解密文件的示例 C 代码

    我正在用 Linux C 编写代码 我需要使用以下命令来加密和解密文件 openssl 目前 我使用系统命令 des3 e nosalt k 0123456789012345 in inp file out out file 进行加密 使用
  • 如何将 Metro 应用部署到桌面?

    我正在尝试将我的 C 应用程序部署到我的 Windows 8 Metro 桌面 我可以在 bin 文件夹中看到部署的文件 但是当我尝试打开它们时 出现以下错误 该应用程序只能在 AppContainer 的上下文中运行 我检查了属性上下文菜
  • 将小数格式化为两位或整数

    对于 10 我想要 10 而不是 10 00 对于 10 11 我想要 10 11 没有代码可以实现吗 即通过指定格式字符串类似于 0 N2 decimal num 10 11M Console WriteLine num ToString
  • 编译器可以报告未知属性的错误吗?即使有范围?

    在N3291 7 6 1 3 5 属性语法和语义 decl attr grammar 关于如何属性是用我读过的源代码写的 使用一个属性范围令牌是有条件支持的 实现定义的行为 and For an 属性标记本国际标准中未指定 该行为是实现定义

随机推荐