Example (Currency is an enum):
public struct MoneyQuantity: IComparable<MoneyQuantity>
{
public Currency Currency { get; }
public decimal Amount { get; }
public MoneyQuantity(Currency currency, decimal amount)
{
Currency = currency;
Amount = amount;
}
public int CompareTo(MoneyQuantity that)
=> Currency == that.Currency ?
Amount.CompareTo(that.Amount) :
throw new InvalidOperationException("Can't compare quantities of money in different currencies");
}
Is this acceptable? Or is it expected that when a type is IComparable, any two instances of the type should be comparable and no exception should be thrown if client code tries to compare them?
I'd count it as a problem, rather than unacceptable. Obviously something that throws on Sort
or any operation that calls into CompareTo()
(including things that users might not realise calls into it) are going to be less useful that things that "just work", so the possibility would have to be well documented (the error message helps). But on the other hand, it's better than something that "just works" in a way that may not be quite correct.
You are forcing users to either avoid such comparisons or work out a way to do the comparison themselves (e.g. converting to a consistent currency for comparisons) but that also forces them to make sure they do so on term that work for them (e.g. doing such conversions according to the rates that they would actually be using). That is likely the best you can do on balance.