Recently I came across this little snippet of code which contains a serious gotcha!
public class Foo
{
public Int32 Amount { get; private set; }
public Foo(Int32 amount)
{
Amount = amount;
}
static public Foo operator +(Foo x, Foo y)
{
x.Amount += y.Amount;
return x;
}
}
This has two problems. Firstly the operator is mutating one of the operands, which is a side effect which probably wasn’t intended by the calling code. Secondly, the operator is returning a reference to one of the operands, which is likely to lead to serious and hard to track down bugs in the calling code. Take this simple usage example:
var x = new Foo(10);
var y = new Foo(20);
var sum = x + y;
Console.WriteLine(x.Amount);
Console.WriteLine(y.Amount);
Console.WriteLine(sum.Amount);
You might expect the output to be:
10
20
30
But in fact the output is:
30
20
30
The operator has mutated ‘x’ and returned a reference to it, such that ‘x’ and ‘sum’ are both referencing the same object.
The operator should be re-written like so:
static public Foo operator +(Foo x, Foo y)
{
return new Foo(x.Amount + y.Amount);
}
To summarize, remember these two simple rules when overriding operators on reference types
- Do not mutate any of the operands.
- Do not return a reference to any of the operands.
