C# 后增量运算符重载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/668763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:36:38  来源:igfitidea点击:

Post-increment Operator Overloading

c#operator-overloading

提问by kiewic

I'm having problems trying to overload the post increment operator in C#. Using integers we get the following results.

我在尝试在 C# 中重载后增量运算符时遇到问题。使用整数我们得到以下结果。

int n;

n = 10;
Console.WriteLine(n); // 10
Console.WriteLine(n++); // 10
Console.WriteLine(n); // 11

n = 10;
Console.WriteLine(n); // 10
Console.WriteLine(++n); // 11
Console.WriteLine(n); // 11

But, when I try it using classes, it looks like the objects are exchanged.

但是,当我使用类尝试它时,看起来对象被交换了。

class Account
{
    public int Balance { get; set; }
    public string Name { get; set; }

    public Account(string name, int balance)
    {
        Balance = balance;
        Name = name;
    }

    public override string ToString()
    {
        return Name + " " + Balance.ToString();
    }

    public static Account operator ++(Account a)
    {
        Account b = new Account("operator ++", a.Balance);
        a.Balance += 1;
        return b;
    }

    public static void Main()
    {
        Account a = new Account("original", 10);

        Console.WriteLine(a); // "original 10"

        Account b = a++;

        Console.WriteLine(b); // "original 11", expected "operator ++ 10"
        Console.WriteLine(a); // "operator ++ 10", expected "original 11"
    }
}

Debugging the application, the overloaded operator method, returns the new object with the old value (10) and the object that has been passed by reference, has the new value (11), but finally the objects are exchanged. Why is this happening?

调试应用程序,重载的运算符方法,返回具有旧值(10)的新对象和通过引用传递的对象,具有新值(11),但最终交换对象。为什么会这样?

采纳答案by Jeromy Irvine

The key is in understanding how the line Account b = a++;works. Given how your code is written, this line is the equivalent of this:

关键在于了解生产线的Account b = a++;工作原理。鉴于您的代码是如何编写的,这一行相当于:

Account b = a;
a++;

And that is the order it will execute in. The assignment effectively(1) happens before the increment. So, the first effect of this line is that aand bboth refer to the original object a.

这就是它将执行的顺序。有效赋值(1)发生在增量之前。所以,这一行的第一个效果是ab都引用了原始对象a

Now the ++ portion will be evaluated. Inside of the operator method, we increment the Balanceof the original object. At this point aand bare both pointing at the original, with a Balanceof 11, and bwill continue to do so.

现在将评估 ++ 部分。在操作符方法内部,我们增加Balance原始对象的 。此时ab都指向原点,aBalance为11,b会继续这样做。

However, you've created a new object inside the operator method and returned it as the output of the operator. awill now be updated to point at the newly created object.

但是,您已经在运算符方法中创建了一个新对象并将其作为运算符的输出返回。a现在将更新为指向新创建的对象。

So, anow points to a new object, while bcontinues to point to the original. That's why the WriteLine output appears swapped.

因此,a现在指向一个新对象,而b继续指向原始对象。这就是 WriteLine 输出出现交换的原因。

As @MarkusQ pointed out, the ++ operator is meant to do in-place modification. By generating a new object, you're breaking that assumption. Operator overloading on objects is a tricky subject, and this is an excellent example of why it's better avoided in most cases.

正如@MarkusQ 指出的那样, ++ 运算符旨在进行就地修改。通过生成一个新对象,你打破了这个假设。对象上的运算符重载是一个棘手的主题,这是一个很好的例子,说明为什么在大多数情况下最好避免这种情况。



1 - Just for accuracy's sake, the assignment does not actually happen before the increment when dealing with operators on objects, but the end result is the same in this case. Actually, the original object reference is copied, the operation is carried out on the original, and then the copied reference is assigned to the left-hand variable. It's just easier to explain if you pretend that assignment happens first.

1 -为了准确起见,在处理对象上的运算符时,赋值实际上不会在增量之前发生,但在这种情况下最终结果是相同的。其实就是复制原始对象引用,对原始对象进行操作,然后将复制的引用赋值给左边的变量。如果你假装分配先发生,解释起来会更容易。

What's really happening is that this:

真正发生的事情是这样的:

Account b = a++;

results in this, due to how the ++ operator works on objects:

由于 ++ 运算符在对象上的工作方式,因此会导致这种情况:

Account copy = a;

Account x = new Account("operator ++", a.Balance);
a.Balance += 1; // original object's Balance is incremented
a = x; // a now points to the new object, copy still points to the original

Account b = copy; // b and copy now point at the same, original, object

回答by MarkusQ

My first thought was to point out that the normal semantics of ++ are in-place modification. If you want to mimic that you'd write:

我的第一个想法是指出 ++ 的正常语义是就地修改。如果你想模仿你会写:

public static Account operator ++(Account a)
{
    a.Balance += 1;
    return a;
}

and not create a new object.

而不是创建一个新对象。

But then I realized that you were trying to mimic the post increment.

但后来我意识到你试图模仿后增量。

So my second thought is "don't do that" -- the semantics don't map well at all onto objects, since the value being "used" is really a mutable storage location. But nobody likes to be told "don't do that" by a random stranger so I'll let Microsoft tell you not to do it. And I fear their word is final on such matters.

所以我的第二个想法是“不要那样做”——语义根本不能很好地映射到对象上,因为被“使用”的值实际上是一个可变的存储位置。但是没有人喜欢被随机陌生人告知“不要那样做”,所以我会让微软告诉你不要那样做。我担心他们在这些问题上的承诺是最终的。

P.S. As to whyit's doing what it does, you're really overriding the preincrement operator, and then using it as ifit were the postincrement operator.

PS 至于它为什么这样做,您实际上是在覆盖预增量运算符,然后将其用作后增量运算符。

回答by Ignacio Vazquez-Abrams

You should always return the changed value. C# uses this as the new value, and returns the old or new value as appropriate for the operator.

您应该始终返回更改后的值。C# 使用它作为新值,并根据运算符返回旧值或新值。