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

dev*_*ium 6 .net c# clr intermediate-language

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

string myString = "abc";
object myObject = myString;
string myStringBack = (string)myObject;
Run Code Online (Sandbox Code Playgroud)

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

.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 
Run Code Online (Sandbox Code Playgroud)

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

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

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

另外,来自C#4.0的以下statamente在Nutshell中是否正确?

Upcasting and downcasting between compatible reference types performs reference
conversions: a new reference is created that points to the same object.
Run Code Online (Sandbox Code Playgroud)

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

谢谢

Eri*_*ert 14

我有一个想法,实际上代码本身不会嵌入任何强制转换代码.

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

try
{
    object x = 123;
    object y = (string)x;
}
catch(InvalidCastException ex)
{ ... }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

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

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

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

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


Ada*_*son 5

你对实例的引用感到困惑.创建新引用,而不是新实例.

object foo = "bar";
string baz = (string)foo;
Run Code Online (Sandbox Code Playgroud)

对字符串的新引用"foo"被赋给baz变量(但是仍然只有一个字符串实例,只是两个变量都指向单个实例).如果不是这种情况,你会有类似"手柄"类型的东西.如果baz并且foo字面上是相同的参考,那么这..

foo = "bim";
Run Code Online (Sandbox Code Playgroud)

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

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

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