User defined implicit conversion of overloaded operator's arguments

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());
        }
    }
}
Jon Skeet
people
quotationmark

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, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:

  • The set of candidate user-defined operators provided by X and Y for the operation operator op(x, y) is determined. The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of ยง7.3.5. If X and Y are the same type, or if X and Y 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);

people

See more on this question at Stackoverflow