The following operator overload is defined inside my Term
class:
public static Term operator *(int c, Term t) {...}
This class also defines an implicit conversion from a Variable
to Term
:
public static implicit operator Term(Variable var) {...}
I would like to understand why the following does not compile:
static void Main(string[] args)
{
Variable var = ...; // the details don't matter
Console.WriteLine(2 * var); // var isn't implicitly converted to Term...
Console.ReadKey();
}
The compiler says:
Operator '*' cannot be applied to operands of type 'int' and 'OOSnake.Variable'
Why isn't my overload of operator *
found?
EDIT: As per the suggestion in the comments, here is a small complete example that re-produces the error:
namespace Temp
{
class A {
}
class B
{
public static implicit operator B(A a) { return new B(); }
public static B operator *(int c, B b) { return new B(); }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(2 * new A());
}
}
}
Basically, operator overload resolution doesn't include implicit user-defined conversions in order to find the operators that could be applicable.
From section 7.3.4 of the C# 5 specification:
An operation of the form
x op y
, whereop
is an overloadable binary operator,x
is an expression of typeX
, andy
is an expression of typeY
, is processed as follows:
- The set of candidate user-defined operators provided by
X
andY
for the operation operatorop(x, y)
is determined. The set consists of the union of the candidate operators provided by X and the candidate operators provided byY
, each determined using the rules of ยง7.3.5. IfX
andY
are the same type, or ifX
andY
are derived from a common base type, then shared candidate operators only occur in the combined set once.
And 7.3.5 doesn't include implicit user-defined conversions in its search for a set of operators.
Note that this also wouldn't work if the implicit conversion to Term
was declared in the Variable
class - although that would be more reasonable to specify and implement, as the compiler could look at the set of conversions from the operand type to other types, and use those for overload resolution.
However, this is only a matter of looking for the operators to start with. The compiler is happy to perform implicit conversions when it considers whether or not an overload is applicable. For example, in your case, if you add:
class A
{
public static B operator *(A a, B b) { return new B(); }
}
Then this is valid:
A a = new A();
Console.WriteLine(a * a);
See more on this question at Stackoverflow