关于运算符重载解析 [英] About operator overload resolution

查看:60
本文介绍了关于运算符重载解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设两个类具有以下隐式和显式运算符模式:

  Foo类{公共静态隐式运算符小数(Foo foo){抛出新的NotImplementedException();}公共静态隐式运算符Foo(十进制值){抛出新的NotImplementedException();}公共静态Foo运算符+(向左Foo,向右Foo){抛出新的NotImplementedException();}}班级酒吧{公共静态显式运算符小数点(Bar bar){抛出新的NotImplementedException();}公共静态显式运算符Foo(Bar bar){抛出新的NotImplementedException();}} 

现在考虑以下代码:

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

隐式键入的 resutlFooAddBar 解析为 Foo ,而add运算符解析为 Foo Foo.operator + .为什么这段代码没有给出模棱两可的错误?运算符本可以同样解析为 decimal decimal.operator + .是因为总是将用户定义的运算符 认为是更合适的?即便如此,考虑到 Bar 具有未使用的 Foo 的显式强制转换,该选择似乎有些奇怪,它将显式定义程序员想要使用的运算符:

var resultFooAddBar = foo +(Foo)bar; //好,我是明确地说我想要 Foo Foo.operator +

如果我们使用第三类 Tango 来定义 Tango Tango.operator +(Tango,Tango),并且使用相同的隐式,而不是 decimal 和显式的运算符模式,然后编译器将引发模棱两可的调用错误.

为什么要区分用户定义的运算符和非用户定义的运算符?

更新:我创建了一个单独的程序集,其中包括以下类,以尝试对Servy的感叹:

 命名空间ExternalAssembly{公开课探戈{公共静态探戈运算符+(探戈左,探戈右){抛出新的NotImplementedException();}}} 

然后在 Foo Bar 中将 decimal 更改为 Tango ,并将所需的引用添加到ExternalAssembly dll.在这种情况下,我仍然得到'+'运算符在操作数'ConsoleApplication.Foo'和'ExternalAssembly.Tango'上是不明确的.为什么在这种情况下,编译器为什么不选择与我最初的问题中的 Foo Foo.operator + 相同的重载 decimal ?

解决方案

重载解析算法具有一系列的更好"指标,通过它们可以确定应使用方法/运算符的多个适用重载中的哪一个.仅当这些度量标准都没有最终最佳"过载时,才会显示歧义错误.

改善的指标之一是所讨论的过载到呼叫站点的定义的紧密度".同一类中的定义比其外部的定义更近",外部类中的定义比该父类型之外的定义更近,同一名称空间中的定义比外部名称空间中的定义更近,等等.您的定义比小数点的 + 运算符更近".(有关此主题的更多信息,请参见本文).

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?

解决方案

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.)

这篇关于关于运算符重载解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆