关于运算符重载决策

时间:2014-09-18 19:25:25

标签: c# operator-overloading overload-resolution

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

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();
    }
}

现在考虑以下代码:

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

隐式输入resutlFooAddBar解析为Foo,添加运算符解析为Foo Foo.operator +。为什么这段代码没有出现含糊不清的错误?运营商可以平等地解决decimal decimal.operator +。是因为用户定义的运算符总是被认为更合适吗?即便如此,选择似乎有点奇怪,考虑到Bar有一个明确的强制转换为Foo未使用哪个将明确定义程序员想要使用的运算符:

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

如果我们使用定义decimal的第三个类Tango以及相同的隐式和显式运算符模式而不是Tango Tango.operator + (Tango, Tango),那么编译器会抛出一个不明确的调用错误。

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

更新:我已经创建了一个单独的程序集,包括以下类来试用Servy的exlanation:

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

然后在decimalTango中将Foo更改为Bar,并将所需的引用添加到ExternalAssembly dll。在这种情况下,我仍然得到' +'操作员对操作数不明确&#;; ConsoleApplication.Foo'和' ExternalAssembly.Tango' 。在这种情况下,为什么编译器不会选择与Foo Foo.operator +原始问题中相同的重载decimal

1 个答案:

答案 0 :(得分:1)

重载分辨率算法具有一系列优点"它们用于确定应该使用方法/运算符的多个适用重载的度量。只有当这些指标中没有一个具有最终的“最佳”时,才会出现这种情况。超载,显示出歧义错误。

更好的衡量指标之一是"亲密度"有问题的重载定义到呼叫站点。同一类中的定义是"更接近"除了它之外的定义,外部类中的定义比该父类型之外的定义更接近,同一名称空间中的定义比外部命名空间中的定义更接近等等。您的定义是“更接近”。比小数的+运算符。 (有关该主题的更多信息,请参阅this article。)