2010-02-03 74 views
9

我已經讀過passng之間的區別,而不是在參數中傳遞ref,但是,我什麼時候想要使用它們?什麼時候通過ref關鍵字

例如,我在一個方法中有一些邏輯可以被重構成它自己的方法。 Resharper 4.5將參數中的一個參數設置爲ref類型,但如果我手動進行重構,我不認爲我會這樣做。

顯然我錯過了一些理解。也許是編碼中的某些類型或某些場景錯過ref關鍵字會發生什麼的例子會有所幫助?

感謝

+1

什麼時候通過'out'? – Natrium 2010-02-03 15:34:51

+0

出於好奇的郵編? – bdd 2010-02-03 15:34:55

+0

@Natrium:我發現時間是在你折騰幾次到很多之後:) – 2010-02-03 15:55:34

回答

8

讓我打破下來到兩個問題:

1)當一個人應該使用REF /輸出形式參數的聲明時,寫一個方法?

使用REF /當你希望你的方法,以便能夠讀取和寫入變量從呼叫者通過,而不是僅僅讀出來。

2)爲什麼「提取方法」重構會產生ref參數?

我不知道Resharper的細節,但我可以猜測。請看下面的邪惡可變的值類型:

struct S 
{ 
    private int x; 
    public int X() { return this.x; } 
    public void M() { this.x += 1; } 
} 

你有一個方法:

void Foo() 
{ 
    S s = new S(); 
    Fred(s); 
    Blah(s); 
    Bar(s); 
    s.M(); 
    Console.WriteLine(s.X()); // prints 1 
} 

和你在中間位「提取方法」:

void NewMethod(ref S s) 
{ 
    Blah(s); 
    Bar(s); 
    s.M(); 
} 

void Foo() 
{ 
    S s = new S(); 
    Fred(s); 
    NewMethod(ref s); 
    Console.WriteLine(s.X()); // still prints 1 
} 

相反,如果你做一個沒有「ref」的方法,然後調用NewMethod(s)會傳遞一個s到NewMethod的副本。請記住,值類型是按值複製的;這就是我們稱之爲「價值類型」的原因。這將是複製得到變異,然後s.X()返回零。重構在程序中引入語義變化是一個壞主意,重構引擎很難知道給定的方法是否依賴於值類型的可變性。

這只是避免可變值類型的另一個原因。

1

傳遞byref纔有用功能的「副作用」:也就是說,你打算修改的值類型的參數,或重新分配另一個目的是給定對象的參數,並有改變生存函數調用。例如:TryGetValue()

否則,最好堅持與byval

+1

實際上'TryGetValue()'使用'out'關鍵字,調用者不需要初始化變量,但被調用者是。在被調用者*可以*改變對象引用的情況下使用'ref'關鍵字。 – 2010-02-03 15:50:24

0

概念上,不同之處在於值類型直接存儲其值,而引用類型存儲對該值的引用。也許你應該重新閱讀一下關於參考和值類型的一些信息。

通過引用傳遞值類型 - 如上所示 - 很有用,但ref對於傳遞引用類型也很有用。這允許被調用的方法修改引用所引用的對象,因爲引用本身是通過引用傳遞的。以下示例顯示,當引用類型作爲ref參數傳遞時,對象本身可以更改。

class RefRefExample 
{ 
    static void Method(ref string s) 
    { 
     s = "changed"; 
    } 
    static void Main() 
    { 
     string str = "original"; 
     Method(ref str); 
     // str is now "changed" 
    } 
} 

MSDN

0

的效果是,在方法中的參數的任何變化將在該變量時控制返回給調用方法中得到反映。所以,如果你想分配給該參數的值,以過去的方式生存調用它的一個可能的用例

0

考慮這個例子:

static int i = 3; 

public static void ChangeIntRef(ref int val) 
{ 
    val = 5; 
} 

public static void ChangeInt(int val) 
{ 
    val = 5; 
} 

Console.WriteLine(i); 
ChangeInt(i); 
Console.WriteLine(i); 

ChangeIntRef(ref i); 
Console.WriteLine(i); 

通過傳遞參數作爲ref,你告訴編譯器,你真正想要的是原來的變量的引用傳遞給方法。結果,該方法可以改變原始變量的值。

如果從上方運行代碼片段,結果是:

3 
3 
5 

這應該清楚地表明,沒有ref關鍵字,則ChangeInt方法不能夠真正改變原有的價值。但是,使用ref關鍵字,ChangeIntRef方法可以更改原始值。

0

我使用語義的引用。考慮這樣的方法:

void AddResultsTable(ref PlaceHolder p) // modifies p; adding a table 
{ 
    var t = new Table(); 

    AddTableHeader(ref t); // modifies t; adding a table header 

    AddTableBody(ref t); // modifies t; adding a table body 

    AddTableFooter(ref t); // modifies t; adding a table footer 

    p.Controls.Add(t); 
} 

AddResultsTable(ref PlaceHolderResults); 

對戰這一項:

Table ReturnTable() 
{ 
    var t new Table(); 

    // AddTableHeader() returns TableHeader 
    t.Columns.HeaderColumns.Add(ReturnTableHeader()); 

    // ... etc. 

    return t; 
} 

PlaceHolder.Controls.Add(ReturnTable()); 

第一個代碼片段看起來比較清爽給我;方法修改對象,而不是返回你必須添加的新對象。它們都保持「裝箱」並隱藏在方法內部。

相關問題