C#postfix和前缀增量/减量重载差异

大多数消息来源说,在c#中重载++和 – 运算符导致一次性重载postfix和prefix。 但看起来他们的行为仍然不同。

class Counter { public Counter(int v = 0) { this.v = v; } public Counter(Counter c) { v = cv; } 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

那么,postfix和前缀增量/减量之间的确切区别是什么以及它如何影响重载? 这些运算符对类和原始类型的作用是否相同?

这是在C#中实现递增和递减的错误方法。 如果你做错了,你会得到疯狂的结果; 你做错了,你得到了疯狂的结果,所以系统工作。 🙂

巧合的是,我上周写了一篇关于这个主题的文章:

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

正如评论者dtb指出的那样,正确的实施是:

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

在C#中,增量运算符不能改变其参数 。 相反,它必须只计算递增的值并返回它,而不会产生任何副作用。 改变变量的副作用将由编译器处理。

有了这个正确的实现,你的程序现在是这样的:

  Counter c1 = new Counter(1); 

调用c1现在引用的对象W Wv是1。

  Counter c2 = c1++; 

这有以下语义:

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

所以c1现在指的是X ,而c2指的是W Wv是1, Xv是2。

  Counter c3 = ++c1; 

这有语义

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

所以c1和c3现在都指向对象Y ,而Yv是3。

  c3++; 

这有语义

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

所以当烟雾全部清除时:

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

X是孤儿。

这应该给出完全相同的结果,就像你将c1c2c3作为正常整数一样。