2013-10-02 51 views
2

大多數消息來源表示,重載++和 - 運算符在c#中的結果會同時重載兩者,postfix和prefix。但看起來他們的行爲仍然不同。C#後綴和前綴增量/減量過載差異

class Counter 
{ 
    public Counter(int v = 0) 
    { 
     this.v = v; 
    } 
    public Counter(Counter c) 
    { 
     v = c.v; 
    } 
    public int GetValue() { return v; } 
    public static Counter operator ++(Counter c) 
    { 
     c.v++; 
     return new Counter(c); 
    } 
    private int v; 
} 


class Program 
{ 
    public static void Main() 
    { 
     Counter c1 = new Counter(1); 

     Counter c2 = c1++; 

     Counter c3 = ++c1; 

     c3++; 

     System.Console.WriteLine("c1 = {0}", c1.GetValue()); 
     System.Console.WriteLine("c2 = {0}", c2.GetValue()); 
     System.Console.WriteLine("c3 = {0}", c3.GetValue()); 
    } 
} 

奇妙的是,雖然過載operator ++返回複製原始類的,在該示例c1c3成爲同一個對象的引用,而c2點不同的一個(c1=4, c2=2, c3=4這裏)。將Counter c3 = ++c1;更改爲Counter c3 = c1++;輸出c1=3, c2=2, c3=4

那麼,後綴和前綴增量/減量之間的確切區別是什麼,以及它如何影響超載?這些運算符是否對類和原始類型採用相同的方式?

+0

您的'operator ++'中存在一個錯誤:您不僅爲遞增的值返回一個對象,而且修改該操作符所應用的對象。它應該是:'公共靜態計數器運算符++(計數器c){返回新的計數器(c.v + 1); }' – dtb

+0

但是這是增量應該做的事情,'我++'必須改變'我'的價值,不是嗎? – Nick

+0

編號'i ++'記得變量'i'的值(我們稱之爲'i_old'),計算值'i + 1'(我們稱之爲'i_new'),將值'i_new'存入變量'i',並返回值'i_old'。 – dtb

回答

9

這是在C#中實現遞增和遞減的錯誤方法。如果你做錯了,你會得到瘋狂的結果;你做錯了,你得到了瘋狂的結果,所以系統工作。 :-)

巧合的是我寫了一篇文章關於這個主題上週:

http://ericlippert.com/2013/09/25/bug-guys-meets-math-from-scratch/

正如評論者DTB指出,正確的實施是:

public static Counter operator ++(Counter c) 
    { 
     return new Counter(c.v + 1); 
    } 

在C#中的增量運營商不得改變其參數。相反,它只能計算遞增的值並返回,而不會產生任何副作用。變量變量的副作用將由編譯器處理。

有了這個正確的執行你的程序是這樣的:

Counter c1 = new Counter(1); 

稱之爲C1指現在W的對象。 W.v爲1

Counter c2 = c1++; 

這具有的語義:

temp = c1 
c1 = operator++(c1) // create object X, set X.v to 2 
c2 = temp 

所以c1現指X,並c2WW.v是1和X.v是2

Counter c3 = ++c1; 

這具有

temp = operator++(c1) // Create object Y, set Y.v to 3 
c1 = temp 
c3 = temp 

所以C1的語義和現在c3分別都是指對象Y,和Y.v是3。

c3++; 

這有

c3 = operator++(c3) // Create object Z, set Z.v to 4 

語義所以當煙霧清除所有:

c1.v = 3 (Y) 
c2.v = 1 (W) 
c3.v = 4 (Z) 

X是孤立的。

這應該給出完全相同的結果,如果您將c1,c2c3視爲正常整數。

+0

在某些方面,'operator' *聲明*使用'++'和'--'作爲「加一」和「減一」操作的名稱,這太糟糕了;我想知道,如果有一個否則無效的標記序列,它會或多或少地混淆[例如, '+%']表示運算符重載計算的值,所以'X = Y +%'會將'X'設置爲由'++ Y'計算的值,但不回寫'Y '。如果存在這樣一個運算符,那麼'+%'超載和前綴/後綴運算符之間的關係會比使用'++'重載更直觀。 – supercat

+0

@supercat:如果存在這樣的操作符,則用戶不太直觀,必須使用它來重載++和 - 。但我同意你的意見,但是,當你重載++和 - 時,你不應該直觀地指出你不應該改變對象。無論哪種方式,那裏都有一些非直覺性。 – RobH

+0

@RobH:我不明白這是多麼的不直觀,除了特殊的編譯器生成的「過載」事件,'+ ='和' - ='操作符被重載重載'+ ''和'-',我不是特別喜歡btw的設計,特別是像'Delegate'這樣的類型,它們的行爲應該像值。如果'evt'是一個自動事件,那麼'evt + = someDelegate'語句會將'someDelegate'自動添加到'evt';它*不等同於'evt = evt + someDelegate;'。不幸的是,沒有辦法讓操作員超載,讓其他代表這樣做。 – supercat