Firstly note that C# will allow a maximum of ONE implicit user-defined conversion between types.
So when you compare two instances of Decibel
, the compiler sees that it can use a user-defined implicit conversion to convert a Decibel
to a double
with which to compare.
However when you compare two instances of Duration
, the compiler cannot find any single implicit conversion which it can use to allow the comparison. The compiler will not consider any user-defined comparison operators for any of the types to which the type can be implicitly converted. It will only look for built-in comparison operators for any of the types to which the type can be implicitly converted.
Therefore the compiler will not use the implicit conversion to TimeSpan
, even though TimeSpan
provides a user-defined comparison operator that could theoretically be used.
Also note that even if the TimeSpan
class provided an implicit conversion to double
, the compiler would still not use it, since it will only consider at most one implicit user-defined conversion in the chain of implicit conversions.
In other words, given these structs:
public struct Number
{
public readonly double Value;
public Number(double value)
{
Value = value;
}
public static implicit operator Number(double duration)
{
return new Number(duration);
}
public static implicit operator double(Number number)
{
return number.Value;
}
}
public struct NumberWrapper
{
public readonly Number Value;
public NumberWrapper(Number value)
{
Value = value;
}
public static implicit operator NumberWrapper(Number duration)
{
return new NumberWrapper(duration);
}
public static implicit operator Number(NumberWrapper number)
{
return number.Value;
}
}
This code will compile:
bool x = new Number(1) < new Number(2);
And so of course will this:
Number n1 = new NumberWrapper(1);
Number n2 = new NumberWrapper(2);
bool z = n1 < n2;
But this won't:
bool y = new NumberWrapper(1) < new NumberWrapper(2);
because NumberWrapper
doesn't have an implicit conversion to any type that supports <
without any further implicit conversions.
Note that all primitive numeric and enumeration types (e.g. char, short, int, long, float, double, decimal, enum) provide built-in comparison operators. All other types can only provide user-defined comparison operators.
User-defined comparison operators look like this:
public static bool operator < (MyType lhs, MyType rhs) ...