2013-11-01 86 views
8

我有以下代碼:方法與價值和參考的參數類型重載

class Calculator 
    { 
     public int Sum(int x, int y) 
     { 
      return x + y; 
     } 



     public int Sum(out int x, out int y) 
     { 
      x = y = 10; 
      return x + y; 
     } 


    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      int x = 10, y = 20; 
      Calculator calculator = new Calculator(); 

      Console.WriteLine (calculator.Sum (x , y)); 
      Console.WriteLine (calculator.Sum (out x , out y)); 

     } 
    } 

此代碼工作做好儘管方法簽名只differenciated是out關鍵字。

但下面的代碼沒有工作:

class Calculator 
    { 

     public int Sum(ref int x, ref int y) 
     { 
      return x + y; 
     } 

     public int Sum(out int x, out int y) 
     { 
      x = y = 10; 
      return x + y; 
     } 

    } 


    class Program 
    { 
     static void Main(string[] args) 
     { 
      int x = 10, y = 20; 
      Calculator calculator = new Calculator(); 

      Console.WriteLine (calculator.Sum (ref x , ref y)); 
      Console.WriteLine (calculator.Sum (out x , out y)); 

     } 
    } 

爲什麼這個代碼不工作? 關鍵字像ref和out方法簽名的一部分嗎?

+0

'ref'和'out'編譯幾乎同樣的事情,所以C#不允許你這樣做。 –

回答

10

out parameter modifier (C# Reference)

儘管ref和out關鍵字引起不同的運行時的行爲, 他們不被認爲是在編譯時間的方法簽名的一部分。因此,方法不能如果唯一的區別是 一個方法需要一個參考參數和其它需要一個出 論點超載。

另見:ref (C# Reference)一類

成員不能有,只有裁判不同, 了簽名。如果一個類型的兩個 構件之間的唯一區別是,它們中的一個具有ref參數和其它 具有一個輸出參數發生編譯錯誤。

+1

如果它們不被認爲是方法簽名的一部分,那麼爲什麼第一個例子工作? –

+2

@DavidS .:基本上,文檔已被打破。他們*被認爲是簽名的一部分,正如我的規格報價表明的那樣。只是出於超載的目的,他們被認爲是簽名中的等價物。 –

+0

編輯並沒有真正令人滿意地回答David的問題,IMO。 C#規範很清楚,參數(值,引用,輸出)*的「種類」是簽名的一部分,但是限制了重載。 –

1

這是由規範。根據MSDN頁out parameter modifier (C# Reference)

雖然裁判和出關鍵字來引起不同的運行時的行爲, 他們不被認爲是在編譯時間的方法簽名的一部分。 因此,方法不能如果唯一的區別是 一個方法需要一個參考參數和其他需要一個out參數超載。 下面的代碼,例如,將不會編譯:

6

要稍有不同引用到其他的答案,這是從C#5說明書中,我發現而不是「參考更清晰,更精確的3.6節引導「:

雖然outref參數改性劑被認爲是簽名的一部分,成員單一類型的聲明中籤名不能相差僅通過ref和out。如果兩個成員在同類型的簽名,這將是相同的,如果與out修飾兩種方法的所有參數改爲ref修飾符聲明發生編譯時錯誤。對於簽名匹配的其他目的(例如隱藏或覆蓋),refout被認爲是簽名的一部分,並且不相互匹配。 (此限制是爲了讓C#程序是很容易轉化爲對通用語言基礎結構(CLI),它並沒有提供一種方法來定義,在refout僅不同方式運行。)

注意參數類型的dynamic略有相似這裏 - 至於CLR而言,這只是一個object類型的參數,所以這是無效的:

void InvalidOverload(object x) {} 
void InvalidOverload(dynamic x) {} 

在這種情況下,但是,對於參數類型爲dynamic的方法,可以覆蓋參數類型爲object或反之亦然的方法 - 重要的一點是,它們相當於調用者,而不是out/ref

-1

它基本上是一個編譯錯誤既是裁判和出幾乎相同。 兩者幾乎相同,但你傳遞一個值參數不需要初始化。

+1

不,他們沒有不「用來發送值類型爲引用類型」 - 這是它如何工作的一個可怕的解釋,並忽略了一個事實,你可以使用'ref'和'參考類型參數out'了。如果原因是用C#處理它們的方式不同,但CLR不這樣做......如果差異得到CLR的支持,那麼超載就沒問題。 –

+0

@Jon Skeet:謝謝喬恩,我會改正它,謝謝你的寶貴意見。 –

+0

現在它只是沒有正確回答原來的問題。你說這是因爲它們幾乎相同 - 但情況很簡單,過載仍然有效。 –