C#后缀和前缀递增/递减超载差异 [英] C# postfix and prefix increment/decrement overloading difference

查看:157
本文介绍了C#后缀和前缀递增/递减超载差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

多数来源称,重载++和 - 在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆