问题
Suppose 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;
The implicitly typed resutlFooAddBar
resolves to Foo
and the add operator resolves to Foo Foo.operator +
. Why doesn't this code give an ambiguous error? The operator could have resolved equally to decimal decimal.operator +
. Is it because user defined operators are always considered a better fit? Even so, the choice seems a bit weird, considering that Bar
has an explicit cast to Foo
that was not used which would explicitly define what operator the programmer would want to use:
var resultFooAddBar = foo + (Foo)bar;
//OK, I'm explicitly saying I want Foo Foo.operator +
If instead of decimal
we use a third class Tango
defining a Tango Tango.operator + (Tango, Tango)
and the same implicit and explicit operator patterns then an ambigous call error is thrown by the compiler.
Why this differentiation between user defined operators and non user defined operators?
UPDATE: I've created a separate assembly including the following class to try out Servy's exlanation:
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 adding the needed reference to the ExternalAssembly dll. In this case I'm still getting a '+' operator is ambiguous on operands 'ConsoleApplication.Foo' and 'ExternalAssembly.Tango'. Why wouldn't the compiler, in this case, choose the same overload Foo Foo.operator +
as in my original question with decimal
?
回答1:
The overload resolution algorithms have a series of "betterness" metrics by which they determine which of mutiple applicable overloads of a method/operator should be used. It is only if none of those metrics has a conclusively "best" overload that there is an ambiguity error shown.
One of the metrics for betterness is the "closeness" of the definition of the overload in question to the call 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 that parent type, definitions in the same namespace are closer than definitions in outer namespaces, etc. Your definition is "closer" than the decimal's +
operator. (See this article for more information on the subject.)
来源:https://stackoverflow.com/questions/25920811/about-operator-overload-resolution