簡體   English   中英

調用值類型的方法

[英]Calling methods on value types

如果我在這里弄錯了,請阻止我。

如果我理解正確,當我在類的實例上調用方法時,JIT編譯器將找到與實例類型相對應的類型對​​象,然后在其中找到實際方法代碼的引用。

我的問題是這對價值類型有何影響? 我的印象是值類型沒有像引用類型那樣的類型對象指針。 如果是這種情況,CLR如何在調用方法時設法導航到方法代碼?

考慮一個例子,假設我們有以下結構:

public struct Test
{
    public void TestMethod()
    {            
    }
}

這是它的IL代碼:

.class public sequential ansi sealed beforefieldinit ConsoleApplication.Test
    extends [mscorlib]System.ValueType
{
    .pack 0
    .size 1

    .method public hidebysig 
        instance void TestMethod () cil managed 
    {
        // Method begins at RVA 0x21dc
        // Code size 1 (0x1)
        .maxstack 8

        IL_0000: ret
    } // end of method Test::TestMethod

}

好的,現在因為C#編譯器靜態地知道Test的類型,它可以進行重載解析並找到被調用的確切TestMethod 然后它發出MSIL以將參數推送到MSIL虛擬堆棧,它需要一個指向Test的類型指針的參數,編譯器在沒有裝箱的情況下處理它並發出包含對該特定方法的元數據引用的調用指令。

.locals init (
        [0] valuetype ConsoleApplication.Test test
    )

IL_0000: ldloca.s test
IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: call instance void ConsoleApplication.Test::TestMethod()

對於ToStringGetHashCode ,編譯器使用Constrained OpCode ,因為這些方法可以重載。

IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: constrained. ConsoleApplication.Test
IL_0010: callvirt instance int32 [mscorlib]System.Object::GetHashCode()

受約束的操作碼允許IL編譯器以統一的方式調用虛函數,而與ptr是值類型還是引用類型無關。 使用約束前綴還可以避免值類型的潛在版本控制問題。 如果未使用約束前綴,則必須發出不同的IL,具體取決於值類型是否覆蓋System.Object的方法。 例如,如果值類型V覆蓋Object.ToString()方法,則會發出調用V.ToString()指令; 如果沒有,則發出一個box指令和一個callvirt Object.ToString()指令。 如果稍后刪除覆蓋,則在前一種情況下可能出現版本控制問題,而在后一種情況下,如果稍​​后添加覆蓋則會出現版本控制問題。

對於GetType方法需要裝箱,因為它是非虛擬的並且在Object類型中定義。

IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloc.0
IL_0009: box ConsoleApplication.Test
IL_000e: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

它被稱為裝箱或自動裝箱,如果您在其上調用某個方法,CLR將自動從值類型實例化相應的類。

更多關於這里這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM