jjzjj

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

coder 2024-05-22 原文

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

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

噢,这会编译,但会在运行时失败。当我们试图将一个对象粘贴到一个字符串 [] 中时。好吧,我同意这很糟糕,但是 T[] 扩展了 Array 并且还实现了 IList (和 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[] 必须在运行时进行类型检查(这违反了您在编译时期望的类型安全性)?为什么当有等效的方法通过上述提供的方法搬起石头砸自己的脚时,阵列显示此属性被认为是有害的?

最佳答案

In .NET reference type arrays are co-variant. This is considered a mistake.

一些人认为类型安全破坏数组协变是 .NET 设计中的一个错误。并不是所有人都这么认为的。我不认为这是一个错误;我认为这是一个不幸的选择。所有设计过程都涉及在不受欢迎的备选方案之间进行选择。在这种情况下,选择是添加一个不安全的隐式转换,对所有数组写入施加运行时成本,还是构建一个无法轻松实现 Java 类型系统的类型系统。这是一个艰难的选择,类型系统的设计者根据他们所掌握的信息做出了他们所能做出的最佳选择。

当然,这种解释只是在乞讨; Java 的设计者犯了一个错误,这难道不是简单的情况吗?可能是,也可能不是; Java 的设计者很可能在类型系统的设计中也面临着权衡。 Java 类型系统开发历史上的任何专家都想在这里插话这些权衡是什么,我很想知道。

凭借十年后见之明,如果 .NET 类型系统的设计者选择避开破坏安全的数组协变,我个人会更喜欢它。但这并不能使那个选择成为“错误”,它只会让它变得有些不幸。

Is the concern that setting to a T[] has to do the type check at runtime (which violates the type-safety you expect at compile time)?

是的。这意味着看起来应该始终成功运行的代码可能会在运行时失败。这意味着正确的代码会受到性能惩罚。

Why is it considered harmful for arrays to exhibit this property when there are equivalent means to shoot yourself in the foot through the provided means above?

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

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

当您绝对肯定地知道您正在做的事情是安全的时候,即使编译器不知道,也会出现违反类型安全的语言和运行时功能。如果您对这些功能的了解程度不足以安全地使用它们,那么请不要使用它们。

关于c# - 为什么数组协方差被认为如此可怕?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4317459/

有关c# - 为什么数组协方差被认为如此可怕?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  6. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  7. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  8. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  9. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  10. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

随机推荐