2014-05-11 183 views
1

我一直在閱讀了一下MSDN上的教程,讓我的頭周圍傳遞通過引用在C#outref並和我遇到下面的代碼示例來了:傳遞通過引用和參考

using System; 

class TheClass 
{ 
    public int x; 
} 

struct TheStruct 
{ 
    public int x; 
} 

class TestClass 
{ 
    public static void structtaker(TheStruct s) 
    { 
     s.x = 5; 
    } 
    public static void classtaker(TheClass c) 
    { 
     c.x = 5; 
    } 
    public static void Main() 
    { 
     TheStruct a = new TheStruct(); 
     TheClass b = new TheClass(); 
     a.x = 1; 
     b.x = 1; 
     structtaker(a); 
     classtaker(b); 
     Console.WriteLine("a.x = {0}", a.x); //prints 1 
     Console.WriteLine("b.x = {0}", b.x); //prints 5 
    } 
} 

從教程的說明到此:

本實施例表明當結構被傳遞給一個方法中, 副本結構被傳遞,但是當一個類的實例被傳遞,參考 是通過。

我完全理解它,但我的問題是,如果引用在C#中傳遞給參數,爲什麼他們需要ref如下面的示例所示:

void tearDown(ref myClass a) 
{ 
    a = null; 
} 

MyClass b = new MyClass(); 
this.tearDown(ref b); 
assert(b == null); 
//b is null 

???我認爲C在C中是一樣的 - 按值傳遞。

+2

僅僅因爲它是一個引用類型,並不意味着它通過引用傳遞。除非明確使用'ref',否則傳遞是有價值的。 –

+0

@JeroenVannevel是的,傳遞是默認值,但傳遞的值是引用類型的引用。 – MarcinJuraszek

+0

部分'MyClass b = new MyClass();'創建2個內存:引用變量'b'和堆上的匿名實例。引用變量的行爲完全像一個值類型(例如'int')。 –

回答

7

在C#中,基本上所有的類都是指針。然而,通過ref/out或不通過就像是將指針傳遞給指針或指針本身。

當您通過一個類(按照第一個示例)時,將繼續對類成員進行任何更改。但是,將參考更改爲對象本身將不會產生結果。假設你更換

public static void classtaker(TheClass c) 
{ 
    c.x = 5; 
} 

隨着

public static void classtaker(TheClass c) 
{ 
    c = new TheClass(); 
    c.x = 5; 
} 

由於c不是outref參數,則你重新分配本地指針cc本身沒有價值。由於您只修改本地c.x,因此在調用此修改後的ClassTaker後,結果將爲b.x == 1。現在

,按照你的第二個例子中,由於是ref參數,更改爲自己將在呼叫範圍可以看出,作爲例子,但價值從呼叫去除ref會導致null斷言失敗。

基本上,ref傳遞通過什麼可以被認爲是指針指向你的指針,而調用沒有ref/out傳遞一個複製的指針到你的對象數據。


編輯:

之所以可以在方法範圍分配c.X是因爲對象c對象X,你會總是得到相同的指針X不管ref的/ out參數與否。相反,ref/out會修改您更改調用作用域所見的值c的能力。

+0

這裏是[教程](http://msdn.microsoft.com/en-us/library/aa288471(v = vs.71).aspx)的鏈接,它顯示了結果。謝謝。 – Unheilig

+0

c.X因爲X是c對象內的指針而發生變化,無論ref.out與否,都可以從方法範圍內進行更改。 ref/out參數只會修改您調用調用範圍所看到的c值的能力。我將把它融入到我的回答中 – David

+0

我真的不知道 - 我比代碼中的理論和術語更熟悉代碼的行爲。爲了猜測,我認爲這是因爲在C#中,一半的行爲是由對象本身(struct vs class)的定義決定的,而不是人們想要的特定方法或實現(按照C++) – David