2013-08-29 20 views
7

我有兩個類FirstProcess和第二處理C#:使用可選參數&命名參數重寫的方法:意想不到的結果

public class FirstProcess 
    { 
     public virtual void Calculate(int x, int y) 
     { 
      Console.WriteLine("First Process X :{0} and Y{1}", x, y); 
     } 
    } 
    public class SecondProcess : FirstProcess 
    { 

     public override void Calculate(int y, int x) 
     { 
      Console.WriteLine("Second Process X :{0} and Y :{1}", x, y); 
     } 
    } 

我稱像計算方法下面

var secondProcess = new SecondProcess(); 
      var firstProcess = (FirstProcess) secondProcess; 

      secondProcess.Calculate(x: 1, y: 2); 
      firstProcess.Calculate(x: 1, y: 2); 

輸出

第二道工序X:1和Y:2

第二個過程X:2和Y:1

我得到了意想不到的結果,即X = 2和Y = 1 .Net如何處理這種情況?爲什麼.net優先考慮命名參數?

回答

9

論證方法調用firstProcess.Calculate(x: 1, y: 2)結合是在編譯時做,但方法分派是在運行時因爲方法virtual

爲了編譯方法調用,編譯器會看到x: 1, y: 2,並且需要將此命名參數列表解析爲順序索引參數列表,以便發出適當的IL(按正確的順序將參數壓入堆棧,然後呼叫方法)。

除了命名參數列表還有一個資料片提供給編譯器:靜態firstProcess,這是FirstProcess。現在我和你都知道,在運行時這將是一個SecondProcess實例,但編譯器不知道(至少在一般情況下)。因此它查找FirstProcess.Calculate的參數列表,並且看到x是第一個參數,y是第二個參數。這使得編譯代碼,如果你寫了

firstProcess.Calculate(1, 2); 

運行,參數12被壓入堆棧和虛擬呼叫到Calculate製成。當然,這最終會調用SecondProcess.Calculate,但參數名稱在轉換到運行時並沒有生存。 SecondProcess.Calculate接受1作爲其第一個參數(y)和2作爲其第二個參數(x),導致觀察結果。

順便說一句,這也是當您使用默認參數值會發生什麼:

public class FirstProcess 
{ 
    public virtual void Calculate(int x = 10) 
    { 
     Console.WriteLine("First Process X :{0}", x); 
    } 
} 

public class SecondProcess : FirstProcess 
{ 
    public override void Calculate(int x = 20) 
    { 
     Console.WriteLine("Second Process X :{0}", x); 
    } 
} 

var secondProcess = new SecondProcess(); 
var firstProcess = (FirstProcess) secondProcess; 

secondProcess.Calculate(); // "Second Process X: 20" 
firstProcess.Calculate(); // "Second Process X: 10" 

這個故事的寓意是:命名和默認參數很方便,但他們的方式是(一定)實現的葉子你打開不愉快的驚喜。當他們提供真正的實際利益時使用它們,而不是在任何時候。

+0

+1我剛剛通過這段代碼,真讓我困惑。感謝您的澄清。 –

+0

真棒解釋..感謝很多jon – JEMI

0

在解析命名參數,編譯器使用靜態類型的方法的調用,而不是動態類型

因此在您的示例中,x指的是第一個參數,而第二個參數指的是y