9

你觉得问题很奇怪吗?是的,发生的事情也很奇怪。让我解释。

我从这个Covariance and Contravariance with C# Arrays中找到了一个片段

string[] strings = new string[1];
object[] objects = strings;
objects[0] = new object();

Jon skeet 解释说上面的代码会 throw ArrayTypeMismatchException,就像它说的那样。

我所做的是我在第 3 行放置了一个断点,使用 DebuggerVisualizer 我手动设置objects[0] = new object()它不会引发任何错误并且它可以工作。稍后检查strings[0].GetType()返回 System.Object。System.Object通过上述过程,不仅可以在 string[] 中设置任何类型。

我不知道这是怎么发生的我提出了我的问题作为评论在那里我看到了这个但没有答案的同一个问题。

很想知道背后发生了什么。任何人都请解释一下。

Edit1 这甚至很有趣

重现上述行为后,试试这个

int len = strings[0].Length;

如果您将鼠标放在属性长度上,则strings[0].Length threw ArgumentException显示消息Cannot find the method on the object instance,但实际上它不会引发异常并且代码运行会产生结果len=0

4

2 回答 2

1

您的示例似乎回答了这个问题:是的,string引用可以引用非字符串对象。然而,这不是有意的。

考虑一下你发现了什么,调试器中的一个错误

正如 Jon Skeet 在您提到的答案中所解释的那样,因为 .NET 数组具有这种“疯狂”的协变,即使数组不是只读的而是更像是读写,每次写入引用数组时,框架都必须检查类型对象的一个​​尝试写入数组,如果ArrayTypeMismatchException您要使用错误的类型,则抛出一个.CatDogDog[]Animal[]

您所展示的是,当我们使用 Visual Studio 调试器的即时窗口(或类似窗口)时,未完成所需的类型检查,因此这可能导致任何类型Y(可能除了指针类型)被分配给任何引用类型 的引用类型变量X。像这样:

X[] arrayOfX = new X[1];
object[] arrayCastByCrazyCovariance = arrayOfX;
Y badObject = new Y();  // or another constructor or method to get a Y

// Set breakpoint here.
// In Immediate window assign:  arrayCastByCrazyCovariance[0] = badObject
// Detach debugger again.

X anomalousReferenceVariable = arrayOfX[0];

anomalousReferenceVariable.MemberOfX();  // or other bad things

这可以使Cat树皮像Dog, 和类似的东西。

在有关绕过类型保护的链接线程中,CodesInChaos 的答案显示了一种不相关的技术,您可以使用该技术将对“错误”和不相关类型的对象的引用放入引用变量中。

于 2013-07-15T08:33:10.567 回答
0

(我更喜欢重写我的答案,因为前一个有太多更新并且不够清楚)。

显然,在 VS 调试部分的其中一个工具(立即窗口)中发现了一个不太完美的行为。这种行为不会影响(完全)代码的正常执行,并且纯粹说,甚至不会影响调试过程。

我在上面最后一句中的意思是,当我调试代码时,我从不使用即时窗口,只需编写我想要的任何代码,执行它并查看调试器显示的内容。提到的问题不会影响这个过程(可以称为“调试实际执行的代码”;在建议的示例中,当您打开时按 F11 objects[0] = new object();),这意味着 VS 中存在严重问题。因此,从我的角度(我所做的调试类型)和执行的角度来看,引用的错误根本没有影响。

此错误的唯一应用是在执行“立即窗口”功能时,这是调试器的一项功能,它在实际交付代码之前估计代码将交付的内容(可能称为“调试未执行的代码”或“估计预期输出来自未执行的代码”等;在建议的示例中,在线objects[0] = new object();,不按 F11,而是使用即时窗口输入值并让此功能告诉您预期会发生什么)。

总之,必须在正确的上下文中理解引用的问题,也就是说,它不是一个全面适用的问题,甚至不是整个调试器的问题(当你在调试器的引用行中按 F11 时,它会输出一个错误,因此调试器确实完全理解这种情况是错误的),但只是在它的一个工具中。我什至不确定此工具是否可以接受这种行为(即,“即时窗口”提供的预测可能不是 100% 正确;如果您想确定会发生什么,请执行代码并让调试器向您显示信息)。

  • 问题:String[] 可以在其中保存 System.Object 吗?
  • 答案:不。
  • 澄清:协方差是一个复杂的现实,VS 中的一些辅助工具(例如,“即时窗口”)可能无法完美地解释它,因此可能存在上述陈述不完全适用的情况。但这是特定工具中的本地行为/错误,对代码的实际执行没有影响。
于 2013-07-14T16:36:15.450 回答