实际铸件在CLR级别如何工作?

时间:2010-05-06 18:38:27

标签: c# .net clr intermediate-language

在进行向上或向下投影时,幕后真的会发生什么?我有一个想法,当做某事时:

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。当你到达执行castclass的代码行时,CLR会尝试进行强制转换。但是,如果我省略了castclass字符串行并尝试运行代码会发生什么呢?
  2. 您不需要castclass。由于所有引用类型都具有类似的内部结构,如果您尝试在Form实例上使用字符串,它将抛出错误用法的异常(因为它检测到Form不是字符串或其任何子类型)。
  3. 另外,Cuts 4.0中的以下statamente是否正确?

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

    它真的会创建一个新的引用吗?我认为它是相同的引用,只存储在不同类型的变量中。

    由于

2 个答案:

答案 0 :(得分:14)

  

我认为实际上不会嵌入任何强制转换代码   在代码本身。

一个有趣的想法。你怎么想象这个有效?

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

如果强制转换不生成代码,那么抛出异常的代码在哪里发生

请记住,从较少特定类型到更具体类型的强制转换的主要用途执行运行时类型检查

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

  

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

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

  

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

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

  

它真的会创建一个新的引用吗?

请记住,在实现级别,引用只是一个指针大小的整数。这是内存管理器可用于跟踪引用数据位置的数字。它可能是一个指针,它可能是一个句柄,它无关紧要;它是实现引用的抽象概念的东西。

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

答案 1 :(得分:5)

你对实例的引用感到困惑。创建了一个新的引用,而不是新实例。

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

字符串"foo"的新引用被分配给baz变量(但是仍然只有一个字符串实例,只是两个变量都指向单个实例)。如果不是这种情况,你会有类似“手柄”类型的东西。如果bazfoo字面意思相同,那么这就是..

foo = "bim";

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

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

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