2011-08-03 96 views
1

在 '通過C#CLR' 的page.170:C#中'this'的含義是什麼?


public sealed class Program { 
    public Int32 GetFive() { return 5; } 
    public static void Main() { 
     Program p = null; 
     Int32 x = p.GetFive(); // In C#, NullReferenceException is thrown 
    } 
} 

理論上,上面的代碼是好的。當然,變量p爲null,但在調用非虛擬方法(GetFive)時,CLR需要知道p的數據類型,即Program。如果 GetFive確實被調用,則此參數的值將爲null。由於在GetFive方法中沒有使用參數 ,因此不會引發NullReferenceException。


請原諒我的愚蠢。我記得CLR通過'this'找到了真正的方法代碼,它總是暗示着方法delcare中的第一個參數,爲什麼它說'調用非虛擬方法(GetFive)時,CLR需要知道p'的數據類型?

+2

Ummmm什麼????? –

+1

但「GetFive」是一種實例方法,不是靜態方法。即使您沒有在「GetFive」方法中使用任何實例變量,運行時仍然需要知道該方法正在執行的對象實例。 – feathj

+0

@Kirk Woll我認爲這段文字是 – saus

回答

5

CLR不會對非虛擬方法執行空檢查。基本上,如果使用call指令調用方法,則CLR不會檢查空指針this。相反,callvirt指令總是檢查無效。但是,無論該方法是否爲虛擬,C#都會發出callvirt指令。

什麼通道的意思是,如果C#編譯器發出的語義上更合適call指令,而不是callvirt指令非虛方法,那麼有問題的代碼不會拋出NullReferenceException。我記得,編譯器團隊決定幾乎總是發出callvirt指令,因爲它更好地處理了版本控制(也是JIT可以將callvirt優化爲call)。

參見http://www.pvle.be/tag/clr/

+1

這本書的引用「編譯器團隊決定幾乎總是發出callvirt指令,因爲它更好地處理了版本控制」 - 主要原因是C#需要在調用方法時拋出NullReferenceExceptions一個空引用。最簡單的方法是使用'callvirt'(它檢查它的參數)而不是'call'。 – porges

+1

儘管我也相信陳述的理由是錯誤的,但C#編譯器對類的所有實例方法調用使用'callvirt'是爲什麼在這裏拋出'NullReferenceException'的正確原因。 –

+0

你所引用的文章對我來說非常有用。非常感謝! –

3

this指本身(類)當前實例。

您的代碼段,

Program p = null; 
Int32 x = p.GetFive(); // In C#, NullReferenceException is thrown 

不工作,因爲你正在試圖調用GetFivenull的方法中,Program一個不存在的實例 - 換句話說,你正在試圖敲門一個空洞,一扇不存在的門。由於CLR不知道門的位置,它會拋出一個異常「找不到功能門!」對你來說 - 比未定義的行爲好得多。

+0

我認爲OP意識到爲什麼在c#中拋出nullreferenceexception,但他的問題是「爲什麼從'CLR'通過C#'這段話說CLR不檢查非虛方法的空值」...編輯:但然後再次,看着問題的標題,我不太確定問題是什麼...... – saus

0

好的。我剛剛通過C#第3版查閱了CLR的第170頁。

也許首頁的整個點是重要部分,其中另一CLR語言編譯器生成一個使用C#類的一些代碼,然後你改變你的C#代碼到一個非虛方法不還重新編譯代碼引用C#庫。在這種情況下,可能會根據調用者是調用callvirt還是callvirt(它不確定編譯器會做什麼)而產生問題。

C#總是默認爲callvirt,所以有沒有問題,但對來電者不能提前知道這一點。如果你這樣做,如果你運送圖書館或API,你可能會無意間破壞某人的程序。


試試這個。

public static Int32 GetFive() { return 5; }  
    public static void Main() {  
     Int32 x = GetFive(); 
    }