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 ++
返回原始类的副本,但在此示例中, c1
和c3
成为对同一对象的引用,而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
是孤儿。
这应该给出完全相同的结果,就像你将c1
, c2
和c3
作为正常整数一样。