About operator overload resolution

Suppose there are two classes with the following implicit and explicit operator pattern:

class Foo
{
    public static implicit operator decimal (Foo foo)
    {
        throw new NotImplementedException();
    }

    public static implicit operator Foo (decimal value)
    {
        throw new NotImplementedException();
    }

    public static Foo operator +(Foo left, Foo right)
    {
        throw new NotImplementedException();
    }
}

class Bar
{
    public static explicit operator decimal (Bar bar)
    {
        throw new NotImplementedException();
    }

    public static explicit operator Foo(Bar bar)
    {
        throw new NotImplementedException();
    }
}

      

Now consider the following code:

var foo = new Foo();
var bar = new Bar();
var resultFooAddBar = foo + (decimal)bar;

      

Implicitly printed resutlFooAddBar

resolves to Foo

, and the append operator resolves to Foo Foo.operator +

. Why doesn't this code give an ambiguous error? The operator could equally resolve decimal decimal.operator +

. Is it because user-defined operators are always considered more appropriate? However, the choice seems a little odd, given that it Bar

has an explicit cast to Foo

, which was not used to explicitly determine which operator the programmer would like to use:

var resultFooAddBar = foo + (Foo)bar;

// OK, I just say what I want Foo Foo.operator +

If instead decimal

we use a third class Tango

defining a Tango Tango.operator + (Tango, Tango)

and the same implicit and explicit operator patterns, then the compiler generates an ambiguous call error.

Why is this the difference between user-defined operators and non-user-defined operations?

UPDATE: I created a separate assembly including the following class to try out ExLa Servy:

namespace ExternalAssembly
{
    public class Tango
    {
        public static Tango operator +(Tango left, Tango right)
        {
            throw new NotImplementedException();
        }
    }
}

      

And then changed decimal

to Tango

in Foo

and Bar

and added the required reference to the ExternalAssembly dll. In this case, I still get the "+" operator ambiguous for the "ConsoleApplication.Foo" and "ExternalAssembly.Tango" operands. Why wouldn't the compiler choose the same overload in this case Foo Foo.operator +

as in my original question with using decimal

?

+3


source to share


1 answer


Overload resolution algorithms have a number of "gloss" metrics by which they determine which of several applicable method / operator overloads should be used. Only if none of these metrics have a definitively "best" overload, an ambiguity error is displayed.



One metric for brilliance is the "proximity" of the definition of the congestion in question to the calling site. A definition in the same class is "closer" than a definition outside of it, a definition in an outer class is closer than definitions outside of this parent type, definitions in the same namespace are closer than definitions in external namespaces, and so on. Your definition is "closer" than the decimal operator +

. (See this article for more information on this matter.)

+1


source







All Articles