About operator overload resolution

自作多情 提交于 2021-02-04 19:09:26

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!