I'm using a struct with 2 properties, and I'm overriding some operators in order to compare, add and subtract them on the basis of their 'amount'.
public struct CurrencyAmount
{
private decimal amount;
private string currency;
public CurrencyAmount(decimal amount, string currency)
{
this.amount = amount;
this.currency = currency;
}
public static decimal operator (CurrencyAmount amount1, CurrencyAmount amount2)
{
if (amount1.currency != amount2.currency) throw new ArgumentException();
return amount1.amount amount2.amount;
}
public static decimal operator -(CurrencyAmount amount1, CurrencyAmount amount2)
{
if (amount1.currency != amount2.currency) throw new ArgumentException();
return amount1.amount - amount2.amount;
}
My problem is that this test doesn't compile:
[Property]
public void Addition_with_same_currency(decimal value1, decimal value2)
{
var amount1 = new CurrencyAmount(value1, "HD");
var amount2 = new CurrencyAmount(value2, "HD");
var expected = new CurrencyAmount(value1 value2, "HD");
Assert.Equal(expected, amount1 amount2);
}
I get a CS1503 error : Argument 1: cannot convert from 'CurrencyAmount' to 'string' and Argument 2: cannot convert from 'decimal' to 'string', from the 'expected' and 'amount1 amount2' parameters respectively.
but this test compiles and passes:
[Property]
public void Addition_is_commutative(decimal value1, decimal value2)
{
var amount1 = new CurrencyAmount(value1, "HD");
var amount2 = new CurrencyAmount(value2, "HD");
Assert.Equal(amount1 amount2, amount2 amount1);
}
So the addition operator appears to be overridden properly. What am I missing here?
CodePudding user response:
amount1 amount2
returns a decimal
and then you are basically trying to equate a CurrencyAmount
with a decimal
.
I would suggest making the
operator return a new CurrencyAmount
:
public static CurrencyAmount operator (CurrencyAmount amount1,
CurrencyAmount amount2)
{
if (amount1.currency != amount2.currency) throw new ArgumentException();
return new CurrencyAmount(amount1.amount amount2.amount, amount1.currency);
}
Another option would be to create an ==
operator that takes a decimal, though you would lose the currency type check:
public static bool operator ==(CurrencyAmount amount1, decimal amount2)
{
return (amount1.amount == amount2);
}
public static bool operator !=(CurrencyAmount amount1, decimal amount2)
{
return (amount1.amount != amount2);
}
And now you could do:
Assert.True(expected == (amount1 amount2));
CodePudding user response:
The reason it is failing to compile is because Assert.AreEqual
requires two objects of the same type. You are passing it a CurrencyAmount
and a decimal
, which are different types.
While DavidG's answer is correct, there is a simpler solution, although it requires you to change the access modifier of CurrencyAmount.amount
. What is the point of a struct with all private members anyway?
My best guess from your code is that you want something like this:
public struct CurrencyAmount
{
public decimal Amount { get; }
public string Currency { get; }
public CurrencyAmount(decimal amount, string currency)
{
Amount = amount;
Currency = currency;
}
public static decimal operator (CurrencyAmount amount1, CurrencyAmount amount2)
{
if (amount1.Currency != amount2.Currency) throw new ArgumentException();
return amount1.Amount amount2.Amount;
}
public static decimal operator -(CurrencyAmount amount1, CurrencyAmount amount2)
{
if (amount1.Currency != amount2.Currency) throw new ArgumentException();
return amount1.Amount - amount2.Amount;
}
}
[Property]
public void Addition_with_same_currency(decimal value1, decimal value2)
{
var amount1 = new CurrencyAmount(value1, "HD");
var amount2 = new CurrencyAmount(value2, "HD");
var expected = new CurrencyAmount(value1 value2, "HD");
Assert.Equal(expected.Amount, amount1 amount2);
}
Also, I think you made a typo by defining the -
operator as -=
.