请考虑以下事项:
using System;
struct FooEnum {
public static implicit operator TypeCode(FooEnum foo) { return TypeCode.Empty; }
}
struct FooDelegate {
public static implicit operator EventHandler(FooDelegate foo) { return null; }
}
struct FooInt {
public static implicit operator int(FooInt foo) { return 0; }
}
class Foo {
public static void Main(string[] args) {
Console.WriteLine(new FooEnum() == new FooEnum()); // CS0019
Console.WriteLine(new FooDelegate() == new FooDelegate()); // OK
Console.WriteLine(new FooInt() == new FooInt()); // OK
}
}
编译它会产生
错误CS0019:运算符'=='无法应用于'FooEnum'和'FooEnum'类型的操作数
使用VC#2005 8.0.50727.8745,csc 4.6.1586.0,Roslyn 1.3.2和Roslyn 2.0.0-rc2进行测试。结果在所有情况下都是一样的。
根据C# language specification 5.0,§7.10:
对于
x op y
形式的操作,其中op是a 比较运算符,重载决策(第7.3.4节)用于选择 特定的运营商实施。操作数转换为 所选运算符的参数类型以及结果的类型 是运算符的返回类型。
所有枚举类型(第7.10.5节),所有委托类型(第7.10.8节)和int
(第7.10.1节)都存在预定义运算符。二元运算符重载决策(第7.3.4节)指定,因为Foo
类型都没有定义自己的相等运算符,
...预定义的二元运算符 op 实现,包括它们的 提升形式,成为候选运营商的集合 操作。给定运算符的预定义实现是 在运营商的描述中指定(§7.8到§7.12)。 对于预定义的枚举和委托运算符,所考虑的唯一运算符是由枚举或委托类型定义的运算符,它们是其中一个操作数的绑定时类型。
(这里“绑定时间”表示编译时,因为不涉及dynamic
个表达式。)
突出显示的句子似乎解释了为什么在选择重载时不考虑隐式转换为TypeCode
(因此FooEnum
案例无效的原因),但是,同样的道理,{ {1}}大小写应该无效,并且调用就好了。 (FooDelegate
是一个无聊的案例,用于证明对预定义运算符的隐式转换被认为是。)
我是否正确阅读了规范,因为FooInt
比较也应该产生错误?如果没有,通过什么顺序的规则是允许的(假设编译器是正确的)以及为什么该序列不允许FooDelegate
(如果这不明显)?