天天看點

.net知識和學習方法系列(二十二)CLR-方法的參數out,ref

因為數值類型的分類是值類型和引用類型,是以方法的參數也有這兩種類型。

值類型參數:

static void Main()

{

  int i=1;

Mehtod(i);

}

static void Method(int s)

  s=200;

如果方法的參數是值類型,調用者Main傳遞給被調用方法Method的是一個值類型的副本,即i的一個副本,i與方法Method中的s值相同,但一旦調用完畢兩都就沒有關系了。

引用類型:

  int[] arri=new int[]{1};

Method(arri);

static void Method(int[] arrs)

  Arrs[0]=200;

引用類型作為方法的參數時,調用者傳遞的是引用(與指針類似),即把arri數組的引用傳給Method方法,這裡隻是把引用傳遞給方法,而非副本,這點就使在Main中的arri與在Method中的arrs引用的是同一個對象,在兩個方法的任何地方使之改變都會影響另一個方法的資料的。

簡單的說,值類型參數傳遞副本,引用類型參數傳遞引用。

接下來說說ref和out作為參數

先看一下下面的代碼,

       static void F1(ref int i)

        {

            i = 100;

        }

        static void F2(out int i)

看看這兩個方法對應的IL

.method private hidebysig static void F1(int32& i) cil managed

 // 代碼大小       6 (0x6)

 .maxstack 8

 IL_0000: nop

 IL_0001: ldarg.0

 IL_0002: ldc.i4.s   100

 IL_0004: stind.i4

 IL_0005: ret

} // end of method Program::F1

.method private hidebysig static void F2([out] int32& i) cil managed

 // 代碼大小       6 (0x6)

} // end of method Program::F2

我們通過生成的中間語言看到,這兩個方法隻有一個差别就是在F2的參數中多了一個[out],方法體中是全部一樣的。其實對于CLR來說,這兩個關鍵字是沒有差別的,都是能以引用類型的方式來操作參數。

為什麼在C#中要區分out和ref呢?主要是因為out是輸入參數,隻希望它從方法内得到值傳回,而ref即要把參數帶到方法,也可以帶出參數,就是說這隻是C#編輯器的願望,是以在C#中是差別的,但在CLR在運得exe的中繼資料是不區另的(因為托管理程式是兩次編譯)。

下面通過另一個方法看看ref和out

static void F1(ref int i)

        static void F1(int i)

上面的代碼放在一個類中是能通過編譯的,因為構成了重載

我們看以看一下普通方法的IL

.method private hidebysig static void F1(int32 i) cil managed

 IL_0001: ldc.i4.s   100

 IL_0003: starg.s    i

最明顯的差别是參數普通方法是int32 i,而加ref,out的是int32& i,參數的不同使重載成為可以。但ref和out,如果參數類型個數相同的話剛形不成重載,因為它們是相同的,不充許出現相同方法(方法的簽名)。

本文轉自桂素偉51CTO部落格,原文連結:http://blog.51cto.com/axzxs/149957 ,如需轉載請自行聯系原作者

繼續閱讀