2012-12-27 167 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獲取實際的對象類型,然後在您的情況下以正確類型的對象作爲字符串類型調用適當的方法。