假设有两个类,具有以下隐式和显式操作符模式:
现在考虑以下代码:
隐式类型的
然后在
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 +
如果我们用第三个类 Tango
(而不是 decimal
),并定义了一个 Tango Tango.operator + (Tango, Tango)
和相同的隐式和显式运算符模式,则编译器会抛出一个模棱两可的调用错误。
为什么会区分用户定义的运算符和非用户定义的运算符?
更新:我创建了一个单独的程序集,包括以下类,以尝试 Servy 的解释:
namespace ExternalAssembly
{
public class Tango
{
public static Tango operator +(Tango left, Tango right)
{
throw new NotImplementedException();
}
}
}
然后在
Foo
和Bar
中将decimal
更改为Tango
,并添加对ExternalAssembly dll的引用。在这种情况下,我仍然得到一个错误信息:"ConsoleApplication.Foo"和“ExternalAssembly.Tango”之间的'+ '运算符不明确。为什么编译器在这种情况下不会选择与我的原始问题中decimal
相同的重载Foo Foo.operator +
呢?请注意,保留了html标签。
decimal
+decimal
。从Foo
到decimal
存在隐式转换,但编译器选择了从decimal
到Foo
的隐式转换。请参见最后一段(刚刚编辑)。 - InBetween