后自增运算符重载
我在尝试重载 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
但是,当我使用类尝试它时,看起来对象被交换了。
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"
}
}
调试应用程序时,重载的运算符方法返回具有旧值 (10) 的新对象,而通过引用传递的对象具有新值 (11),但最终对象被交换。 为什么会发生这种情况?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我的第一个想法是指出 ++ 的正常语义是就地修改。 如果你想模仿你会写:
而不是创建一个新对象。
但后来我意识到你试图模仿后期增量。
所以我的第二个想法是“不要这样做”——语义根本不能很好地映射到对象上,因为“使用”的值实际上是一个可变的存储位置。 但没有人喜欢被随机的陌生人告诉“不要这样做”,所以我会让 微软告诉你不要这样做。 我担心他们对此类问题的决定是最终的。
PS 至于为什么它这样做,你实际上是重写了前增量运算符,然后使用它就像它是后增量运算符。
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:
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 why it's doing what it does, you're really overriding the preincrement operator, and then using it as if it were the postincrement operator.
关键在于理解
Account b = a++;
行的工作原理。 考虑到代码的编写方式,这一行与此等效:这就是它将执行的顺序。有效赋值(1)发生在增量之前。 因此,这一行的第一个效果是 a 和 b 都引用原始对象 a。
现在将评估 ++ 部分。 在运算符方法内部,我们增加原始对象的
Balance
。 此时,a 和 b 都指向原始数据,Balance
为 11,b 将继续这样做。但是,您已在运算符方法内创建了一个新对象,并将其作为运算符的输出返回。 a 现在将更新为指向新创建的对象。
因此,a 现在指向一个新对象,而 b 继续指向原始对象。 这就是 WriteLine 输出出现交换的原因。
正如 @MarkusQ 指出的, ++ 运算符旨在进行就地修改。 通过生成一个新对象,您就打破了这个假设。 对象上的运算符重载是一个棘手的主题,这是一个很好的例子,说明了为什么在大多数情况下最好避免重载。
1 - 为了准确起见,在处理对象上的运算符时,赋值实际上并不发生在增量之前,但在这种情况下最终结果是相同的。 实际上,复制了原始对象引用,对原始对象进行操作,然后将复制的引用分配给左侧变量。 如果你假装赋值首先发生,那么解释起来会更容易。
真正发生的是:
由于 ++ 运算符在对象上的工作方式,结果是这样的:
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: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 a and b both refer to the original object a.
Now the ++ portion will be evaluated. Inside of the operator method, we increment the
Balance
of the original object. At this point a and b are both pointing at the original, with aBalance
of 11, and b will continue to do so.However, you've created a new object inside the operator method and returned it as the output of the operator. a will now be updated to point at the newly created object.
So, a now points to a new object, while b continues to point to the original. That's why the WriteLine output appears swapped.
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.
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.
What's really happening is that this:
results in this, due to how the ++ operator works on objects:
您应该始终返回更改后的值。 C# 使用此值作为新值,并根据运算符返回旧值或新值。
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.