2012-12-27 176 views
8

可能重复:
C# “as” cast vs classic cast什么是引擎盖下铸造

我想知道.NET CLR的引擎盖下会发生什么,当我这样做

 
object myObj = "abc"; 
string myStr = (string)myObj; 

以及第二行如何与string myStr = myObj.ToString()string myStr = myObj as string;

四处张望我发现泛型的答案,例如“编译器在那里插入代码”,但我不满意......我正在寻找转换机制的深刻理解......编译器插入代码?给我看看!编译器优化代码?怎么样?什么时候?

请尽量靠近金属!

+0

你看过制作的这个演员阵容吗? – Oded

+0

我想严格来说,一个强制转换将是'string myStr = myObj'作为字符串;'也许答案可以包括差异(就CLR而言......) – EtherDragon

+1

@EtherDragon - 'as'更像是一个“尝试强制转换”。 OP的语法当然是一个演员。 – Oded

回答

3

您可以使用IL Dissasembler来查看代码在较低级别生成的内容。如果您的计算机上安装了Visual Studio,只需在Windows搜索框中输入“ildasm”即可找到它。

这里是下面的代码的IL样子:

object myObj = "abc"; 
string myStr = (string)myObj;  
string tostring = myObj.ToString(); 

enter image description here

+2

好像我必须深入下去......“IL_0008:castclass [mscorlib] System.String”看起来像另一个抽象层... – Leonardo

+0

@Leonardo'castclass'是一个msil操作码。在抖动将其转换为二进制之前,它不会降低。 – asawyer

+2

@Leonardo这就像我愿意进入这些东西一样深刻:)。 http://en.wikipedia.org/wiki/Common_Intermediate_Language这里有对STLOC等命令的解释。 – Thousand

2

一投主要是一个编译时间结构。这是告诉编译器的方式,“我比你更了解这个实例,你认为这种类型实际上是另一种类型,只是假装它是另一种类型,让我使用所有的类型其他类型的方法/属性/字段等等

在运行时几乎没有什么变化,几乎所有添加的东西都是一个检查,以确保该实例真的是您想要转换的类型对,如果它是不是会抛出一个异常,这是或多或少:。

if(myObj.GetType() != typeof(string)) 
    throw new ClassCastException(); 

至于ToString,它只是一个返回string方法的string内c它的定义lass最有可能只是return this;。在任何情况下,你在技术上没有施放任何东西,你只是调用每个对象都返回一个字符串的方法,并且当该对象是引擎盖下的string时,你恰好碰到相同的对象。关键是编译器知道方法调用的结果总是一个字符串,所以没有什么特别的需要做。

1

您可以使用Visual Studio附带的ILDASM。它是一个IL反汇编程序。

下面是代码:

public void Foo() 
{ 
    object myObj = "abc"; 
    string myStr = (string)myObj; 
} 

这里是我的了:

.method public hidebysig instance void Foo() cil managed 
{ 
    // Code size  15 (0xf) 
    .maxstack 1 
    .locals init ([0] object myObj, 
      [1] string myStr) 
    IL_0000: nop 
    IL_0001: ldstr  "abc" 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: castclass [mscorlib]System.String 
    IL_000d: stloc.1 
    IL_000e: ret 
} // end of method ShowWhatCastIs::Foo 

随着toString()方法:

public void Foo2() 
{ 
    object myObj = "abc"; 
    string myStr = myObj.ToString(); 
} 

的IL是:

.method public hidebysig instance void Foo2() cil managed 
{ 
    // Code size  15 (0xf) 
    .maxstack 1 
    .locals init ([0] object myObj, 
      [1] string myStr) 
    IL_0000: nop 
    IL_0001: ldstr  "abc" 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_000d: stloc.1 
    IL_000e: ret 
} // end of method ShowWhatCastIs::Foo2 

当您将字符串“abc”存储在位置0中时,则会加载位置0,使用“cast class [mscorlib] System.String”强制转换该值,然后将该值存储到位置1

当您致电.ToString()它虚拟地在字符串上调用System.Object.ToString()。 toString()方法在System.String

定义下面是System.String.ToString()的ILDASM:

.method public hidebysig virtual instance string 
     ToString() cil managed 
{ 
    .custom instance void System.Runtime.TargetedPatchingOptOutAttribute::.ctor(string) = (01 00 3B 50 65 72 66 6F 72 6D 61 6E 63 65 20 63 // ..;Performance c 
                          72 69 74 69 63 61 6C 20 74 6F 20 69 6E 6C 69 6E // ritical to inlin 
                          65 20 61 63 72 6F 73 73 20 4E 47 65 6E 20 69 6D // e across NGen im 
                          61 67 65 20 62 6F 75 6E 64 61 72 69 65 73 00 00) // age boundaries.. 
    .custom instance void __DynamicallyInvokableAttribute::.ctor() = (01 00 00 00) 
    // Code size  2 (0x2) 
    .maxstack 8 
    IL_0000: ldarg.0 
    IL_0001: ret 
} // end of method String::ToString 

它只返回本身。

1

CLR允许您将对象转换为其类型或其任何基类型。转换为基本类型已经被认为是安全的并且是隐含的。

例如。

Object s = new String();

但CLR要你指定明确的转换转换为派生类型

String str = s; // Give error and needs you to explicitly cast it 
//To get it to work 
String str = (String)s; 

现在,这里会发生什么它s没有转换为字符串时,但检查是否是String类型与否。如果发现它是String类型,则转换为成功,否则抛出InvalidCastExcetion。

两个更多的方式来情况下使用运营商

是接线员:我如果转换成功,否则为false返回true。

例如

Object o = new Object(); 
Boolean b1 = (o is Object); // b1 is true 
Boolean b2 = (o is DateTime); // b2 is false 

所以调用任何方法之前,通常你会写这样的代码

if(o is DateTime) // Check this by observing the object 
{ 
    DateTime d = (DateTime)o; // Again cast the object to obtain a reference 
    // Perform operations 
} 

这是一个有点贵,因为CLR施放两次。

为了避免这种情况,我们有作为运营商。

作为运算符:返回对检查对象类型的引用else else返回null。

例如:

DateTime d = o as DateTime; // Check the object to verify the case and returns reference to the object itself or null 

if(d != null) 
{ 
    // Perform the operations 
} 

所以你可以看到,使用as操作符时会有轻微的性能提升。

这就是CLR在铸造类型时所提供的全部内容。


当涉及到你的代码:

对象STR = “ABC”;

str.ToString()将调用System.object类的ToString方法,该方法是一种虚拟方法。当调用一个虚拟方法时,CLR实际上会检查调用者所指向的对象的类型。

这里的str实际上是指向一个字符串对象。 因此,编译器将生成代码来调用String类的ToString方法,该方法将打印“abc”作为输出。 这个概念是多态性,其中当调用任何类型的虚拟方法时,首先由CLR获取实际的对象类型,然后在您的情况下以正确类型的对象作为字符串类型调用适当的方法。