6

在进行向上或向下转换时,幕后究竟发生了什么?我的想法是,在做某事时:

string myString = "abc";
object myObject = myString;
string myStringBack = (string)myObject;

最后一行中的强制转换的唯一目的是告诉编译器我们是安全的,我们没有做错任何事情。所以,我的想法是,实际上不会在代码本身中嵌入任何转换代码。看来我错了:

.maxstack 1
.locals init (
    [0] string myString,
    [1] object myObject,
    [2] string myStringBack)
L_0000: nop 
L_0001: ldstr "abc"
L_0006: stloc.0 
L_0007: ldloc.0 
L_0008: stloc.1 
L_0009: ldloc.1 
L_000a: castclass string
L_000f: stloc.2 
L_0010: ret 

为什么 CLR 需要类似的东西castclass string

向下转换有两种可能的实现:

  1. 您需要一个castclass something. 当您到达执行 的代码行时,castclassCLR 会尝试进行强制转换。但是,如果我省略了 castclass 字符串行并尝试运行代码会发生什么?
  2. 您不需要castclass. 由于所有引用类型都具有相似的内部结构,如果您尝试在 Form 实例上使用字符串,它将抛出错误使用异常(因为它检测到 Form 不是字符串或其任何子类型)。

此外,简而言之,C# 4.0 中的以下陈述是否正确?

Upcasting and downcasting between compatible reference types performs reference
conversions: a new reference is created that points to the same object.

它真的创造了一个新的参考吗?我认为这将是相同的引用,只是存储在不同类型的变量中。

谢谢

4

2 回答 2

13

我的想法是,实际上不会在代码本身中嵌入任何转换代码。

一个有趣的想法。你是如何想象这会奏效的?

try
{
    object x = 123;
    object y = (string)x;
}
catch(InvalidCastException ex)
{ ... }

如果演员表不产生任何代码,那么引发异常的代码在哪里发生

请记住,从不太具体的类型转换为更具体的类型的主要目的执行运行时类型检查

一旦类型检查通过,那么肯定不会发生其他任何事情。类型检查前的引用位和类型检查后的位是相同的位;我们刚刚让运行时验证旧位的新用法是合理的。

如果您尝试在 Form 实例上使用字符串,它将引发错误使用异常(因为它检测到 Form 不是字符串或其任何子类型)。

它在哪里检测到?我的意思是,究竟是在哪条指令中检测到的?在 castclass 指令中。这就是 castclass 指令的用途。

如果我省略了 castclass 字符串行并尝试运行代码会发生什么?

类型安全验证器会拒绝您的程序。如果您强制 CLR 在未通过验证的情况下运行它,那么它将具有未定义的行为。它可能成功了,也可能失败了,它可能已经格式化了你的硬盘。

它真的创造了一个新的参考吗?

请记住,在实现级别,引用只是一个指针大小的整数。这是内存管理器可以用来跟踪引用数据的位置的数字。它可能是一个指针,它可能是一个句柄,不管它是什么;它实现了引用的抽象概念。

当您有一个包含 12 的变量并将其内容“替换”为 12 时,这是刚刚创建的“新”12 还是“旧”12?假设您创建了第二个变量,并通过从第一个变量复制将 12 也放入其中。那是“新” 12 还是“旧” 12?你怎么知道?这是一个没有区别的区别。当您创建与“旧”引用相同的“新”引用时,是否会创建新的东西?这个问题是一个哲学问题,而不是一个技术问题。

于 2010-05-06T23:00:00.937 回答
5

您将参考与实例混淆了。创建一个新的引用,而不是一个新的实例。

object foo = "bar";
string baz = (string)foo;

对字符串的新引用"foo"被分配给baz变量(但仍然只有一个字符串实例,只是两个变量都指向单个实例)。如果不是这种情况,您将拥有类似于“句柄”类型的东西。如果bazfoo从字面上看是相同的参考,那么这个..

foo = "bim";

也会使baz等于"bim"(同样,分配非字符串类型将baz不再指向有效的字符串引用)。

当引用类型处于相同的继承层次结构(一个直接或间接从另一个继承)或存在类型之间的显式转换时,您可以对引用类型执行强制转换。请注意,与所有其他运算符一样,显式转换不是多态的——也就是说,必须在所讨论的类之一上专门定义转换,而不是在层次结构的另一点上定义。

显式转换(如果存在)将优先考虑,即使相关类型在没有它的情况下也是兼容的。在显式转换的情况下,您无法保证(实际上,这不太可能)转换/转换的结果将指向与被转换对象相同的实例。

于 2010-05-06T18:44:21.610 回答