C#后缀和前缀递增/递减超载差异 [英] C# postfix and prefix increment/decrement overloading difference
问题描述
多数来源称,重载++和 - 在C#操作结果都超载,后缀和前缀一次。但它看起来像他们的行为仍然是不同的。
类柜台
{
公共计数器(INT v = 0)
{
this.v = v;
}
公共计数器(计数器C)
{
V = C.V;
}
公众诠释的GetValue(){返回伏; }
公共静态计数器符++(计数器C)
{
C.V ++;
返回新的计数器(C);
}
私人诠释伏;
}
类节目
{
公共静态无效的主要()
{
计数器C1 =新的计数器(1 );
计数器C2 = C1 ++;
计数器C3 = C1 +;
C3 ++;
的System.Console.WriteLine(C1 = {0},c1.GetValue());
的System.Console.WriteLine(C2 = {0},c2.GetValue());
的System.Console.WriteLine(C3 = {0},c3.GetValue());
}
}
奇妙的是,虽然超载运营商++
返回复制原始类的,在这个例子中 C1
和 C3
引用变对同一个对象,而 C2
指向不同的一个( C1 = 4,C2 = 2,C3 = 4
点击这里)。更改计数器C3 = ++ C1;
到计数器C3 = C1 ++;
输出 C1 = 3 ,C2 = 2,C3 = 4
。
那么,是什么后缀和前缀递增/递减以及它如何影响超载之间准确的区别?这些运营商的行为类和基本类型一样吗?
这是C#实现递增和递减的方式不对。您将获得疯狂的结果,如果你这样做不对;你没有错,你疯了结果,所以该系统的工作原理。 : - )
无独有偶我写了一篇关于这个主题上周:
的http://ericlippert.com/2013/09/25/bug-guys-meets-math-从划痕/
作为评论者DTB指出,正确的实现是:
公共静态计数器符++(计数器C)
{
返回新的计数器(CV + 1);
}
在C#中的增量运算符的必须发生变异它的参数。相反,它必须仅计算增加后的值,并返回它,而不产生任何副作用。 。变异变量的副作用将被编译器处理
通过这个正确的执行你的程序,现在是这样的:
计数器C1 =新的计数器(1);
调用对象C1指的是现在是W
。 W.v
1
计数器C2 = C1 ++;
这具有的语义:
TEMP = C1
C1 =符++(C1)//创建对象X,设置第十五2
C2 =临时
所以 C1
现指 X
和 C2
指是W
。 Wv的
1和第十五
2
计数器C3 = C1 +;
这有
<$ P $的语义p>
TEMP =符++(C1)//创建对象Y,设置YV 3
C1 =临时
C3 =临时
所以C1和现在c3分别指的对象是
和 YV
3
C3 ++;
这有
<$ P $的语义p>
C3 =运算符++(C3)//创建对象Z,设置ZV 4
所以,当烟雾清除所有:
c1.v = 3(Y)
c2.v = 1(W)
c3.v = 4(Z)
和 X
是孤立的。
这正是应该给予相同的结果,如果你喝了 C1
, C2
和 C3
正常整数。
Most sources says that overloading ++ and -- operators in c# results overloading both, postfix and prefix at once. But it looks like their behaviour is still different.
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());
}
}
Wonderfully, although overloaded operator ++
returns copy of the original class, in this example c1
and c3
becomes references to the same object, while c2
points to different one (c1=4, c2=2, c3=4
here). Changing Counter c3 = ++c1;
to Counter c3 = c1++;
outputs c1=3, c2=2, c3=4
.
So, what is the exact difference between postfix and prefix increment/decrement and how it affects overloading? Are these operators acts same way for classes and for primitive types?
This is the wrong way to implement increment and decrement in C#. You will get crazy results if you do it wrong; you did it wrong, you got crazy results, so the system works. :-)
Coincidentally I wrote an article about this very subject last week:
http://ericlippert.com/2013/09/25/bug-guys-meets-math-from-scratch/
As commenter dtb points out, the correct implementation is:
public static Counter operator ++(Counter c)
{
return new Counter(c.v + 1);
}
In C# the increment operator must not mutate its argument. Rather it must only compute the incremented value and return it, without producing any side effects. The side effect of mutating the variable will be handled by the compiler.
With this correct implementation your program now goes like this:
Counter c1 = new Counter(1);
Call the object that c1 refers to right now W
. W.v
is 1.
Counter c2 = c1++;
This has the semantics of:
temp = c1
c1 = operator++(c1) // create object X, set X.v to 2
c2 = temp
So c1
now refers to X
, and c2
refers to W
. W.v
is 1 and X.v
is 2.
Counter c3 = ++c1;
This has the semantics of
temp = operator++(c1) // Create object Y, set Y.v to 3
c1 = temp
c3 = temp
So c1 and c3 now both refer to object Y
, and Y.v
is 3.
c3++;
This has the semantics of
c3 = operator++(c3) // Create object Z, set Z.v to 4
So when the smoke all clears:
c1.v = 3 (Y)
c2.v = 1 (W)
c3.v = 4 (Z)
and X
is orphaned.
This should give exactly the same results as if you'd had c1
, c2
and c3
as normal integers.
这篇关于C#后缀和前缀递增/递减超载差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!