2013-04-19 41 views
6

使用refout參數調用方法時,必須在調用方法時指定適當的關鍵字。我明白,從風格和代碼質量的角度來看(例如,解釋爲here),但我很好奇在調用程序中是否還需要指定關鍵字。是否有技術原因要求在呼叫者「出」和「ref」關鍵字?

例如:

static void Main() 
{ 
    int y = 0; 
    Increment(ref y); // Is there any technical reason to include ref here? 
} 

static void Increment(ref int x) 
{ 
    x++; 
} 

回答

11

如果您問是否可以設計該語言,以便在呼叫站點不需要這些語言,那麼答案是肯定的。沒有特別的理由,他們不能被排除在外。編譯器從元數據中獲得所需的所有信息,因此可以進行適當的轉換。

也就是說,這樣做會使得它不可能有兩個重載:

public void DoSomething(int x); 
public void DoSomething(ref int x); 

,編譯器將無法消除歧義這一點。

儘管refout可能已經變爲可選,在這種情況下,這些重載將被允許。編譯器可以採用默認值(即non-ref),或者發出一個模糊錯誤,並讓你指定你真正想要的是哪一個。

所有這一切說,我必須在呼叫站點指定refout。它告訴我該參數可能會被修改。在Pascal工作了很多年,其中var參數的傳遞方式與傳遞值參數的方式相同(在調用站點的語法相同),我更喜歡C#在這方面的特殊性。

+1

謝謝吉姆。這正是我所要求的。我只是想確保我沒有失蹤。至於超負荷的解決方案,我不確定不允許超負荷會是一件壞事! –

+1

或許應該提到你不能用'DoSomething(out int x)'重載'DoSomething(ref int x)',反之亦然。 – Izzy

12

唯一的技術原因,我能想到的是重載解析:你可以有

static void Increment(ref int x) 

static void Increment(int x) 

This is allowed;在調用中沒有ref,編譯器將無法區分它們。

+0

我幾乎沒有發佈這個自己。 – Snixtor

+0

確實如此,但是您能否提供一個超載實際上很理智的例子?我不能拿出一個。 –

+3

@JasonWatkins當你建立一個通信庫,可以以「post and forget」模式向服務器發佈新值,或發佈一個新值,等待響應並寫入返回值返回到'ref'參數。就我個人而言,我會給出兩個不同的名字,但由於兩者的語義足夠接近,我可以購買一個論證,即超載是有必要的。 – dasblinkenlight

9

需要修改器的另一個原因是將參數更改爲refout a 重大更改。如果可以推斷出這個ref/out,那麼一個邪惡的程序員會將這個參數從一個參數改變爲一個參考值,而這個客戶端將不會檢測到這個新簽名。如果客戶端調用的方法

public int Increment(int x) 
{ 
    return x + 1; 
} 

使用

int result = Increment(x); 

假設一個邪惡的開發商決定改變,而不是改變按引用傳遞的價值和回報的錯誤代碼如果說的落實,增量導致溢出:

public int Increment(ref int x) 
{ 
    x = x + 1; 
    if(x == int.MinValue) // overflow 
     return -1; 
    else 
     return 0; 
} 

然後客戶端建立反對簽名不會收到編譯錯誤,但幾乎肯定會中斷調用應用程序。

-1

編譯器需要知道它在構建IL時解釋的方法參數。 一個原因是,如過載:

public void (ref int x) {} 
public void (int x)  {} 

另一個原因是out將明確允許您使用傳遞由值參數使用方法外的解釋值。 ref將指向該參數,從而指出該方法的任何新值到相同的內存位置