在 .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(使用前将#替换为@)