如果有的话,以下哪种转换相等的情况是错误的?

Jer*_*ert 5 c# operator-overloading language-lawyer

考虑以下:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

编译这将产生

错误 CS0019:运算符“==”不能应用于“FooEnum”和“FooEnum”类型的操作数

使用 VC# 2005 8.0.50727.8745、csc 4.6.1586.0、Roslyn 1.3.2 和 Roslyn 2.0.0-rc2 进行测试。结果在所有情况下都是相同的。

根据C# 语言规范 5.0 §7.10:

对于形式为 的操作,其中 op 是比较运算符,重载决议(第 7.3.4 节)用于选择特定的运算符实现。操作数转换为所选运算符的参数类型,结果类型为运算符的返回类型。x op y

所有枚举类型(第 7.10.5 节)、所有委托类型(第 7.10.8 节)和 for int(第 7.10.1 节)都存在预定义的运算符。二元运算符重载决议(第 7.3.4 节)指定,由于没有任何Foo类型定义自己的相等运算符,

...预定义的二元运算符op实现,包括它们的提升形式,成为该操作的候选运算符集。给定运算符的预定义实现在运算符的描述中指定(第 7.8 节到第 7.12 节)。 对于预定义的枚举和委托运算符,唯一考虑的运算符是由作为操作数之一的绑定时间类型的枚举或委托类型定义的运算符。

(这里的“绑定时间”是指编译时间,因为不dynamic涉及表达式。)

突出显示的句子似乎解释了为什么TypeCode在选择重载时不考虑隐式转换 to (因此为什么FooEnumcase 无效),但是,出于同样的原因,FooDelegatecase 应该是无效的,并且调用得很好。(这FooInt是一个无聊的例子,用于证明考虑到预定义运算符的隐式转换。)

我是否正确阅读了规范,因为FooDelegate比较也应该产生错误?如果不是,允许的规则序列是什么(假设编译器是正确的),为什么该序列不允许FooEnum(如果这不明显)?