为什么不相关的c#接口引用可以在没有编译器错误的情况下进行比较?

为什么不相关的c#接口引用可以在没有编译器错误的情况下进行比较?,c#,interface,C#,Interface,我最近很惊讶地发现编译器在比较接口引用方面显然不严格,我想知道为什么它是这样工作的 考虑以下代码: class Program { interface I1 {} interface I2 {} class C1 : I1 {} class C2 : I2 {} static void Main(string[] args) { C1 c1 = new C1(); C2 c2 = new C2();

我最近很惊讶地发现编译器在比较接口引用方面显然不严格,我想知道为什么它是这样工作的

考虑以下代码:

class Program
{
    interface I1 {}
    interface I2 {}
    class C1 : I1 {}
    class C2 : I2 {}

    static void Main(string[] args)
    {
        C1 c1 = new C1();
        C2 c2 = new C2();

        I1 i1 = c1;
        I2 i2 = c2;

        bool x = c1 == c2;
        bool y = i1 == i2;
    }
}
编译器说我不能比较下面的
c1==c2
。这些类型完全不相关。然而,它确实允许我比较
i1==i2
。我希望它会在编译时出错,但我惊讶地发现,您可以将任何接口与任何其他接口进行比较,编译器永远不会抱怨。例如,我可以比较
(I1)null==(IDisposable)null
,没有问题

接口不是对象吗?它们是一种特殊的参考类型吗?我的期望是,
=
将导致直接引用比较或调用具体类的虚拟Equals


我遗漏了什么?

我想这样做是因为您可以让一个类型继承两个接口,对于这种情况,这种比较可能很有用:

interface I1 {}
interface I2 {}
class C1 : I1, I2 {}
所以在第一种情况下,编译器肯定知道对象是不同的,但在第二种情况下,它们可能不是

我的期望是a==将导致直接引用比较或调用具体类的虚拟Equals


这是真的,但编译器不知道这一点。这将在运行时确定。

这在C语言规范第7.9.6章“引用类型相等运算符”中有很好的描述:

预定义的引用类型相等 营办商包括:

布尔运算符==(对象x,对象y);
布尔运算符=(对象x, 对象y)

操作员返回 比较两个参考文献的结果 平等或不平等

自 预定义的引用类型相等 运算符接受类型为的操作数 对象,它们适用于 不要声明适用的操作员== 还有接线员!=成员。相反地 任何适用的用户定义的等式 操作员有效地隐藏了 预定义引用类型相等 接线员

预定义的引用 类型相等运算符需要以下操作之一: 以下内容:
•两个操作数都是 引用类型值或文本 无效的此外,标准隐式 转换(§6.3.1)存在于 将任一操作数的类型转换为 另一个操作数。
•一个操作数是一个 类型T的值,其中T为a 类型参数和其他操作数 是文本null。此外,T 没有值类型 约束

除非其中一个 条件为true,编译时 发生错误。显著影响 这些规则是:
•它是一个 使用 预定义引用类型相等 运算符来比较两个引用 这是众所周知的在不同的时间 编译时。例如,如果 操作数的编译时类型为 两类A和B,如果 A和B都不是从 其他的,那就不可能了 两个操作数引用相同的值 对象因此,该操作非常简单 被认为是编译时错误


最后一段是出现错误的原因。

首先,请注意Hans引用的是规范的正确部分,但他引用的规范版本有一个与您的问题相关的打字错误。修正后的C#4规范规定:

预定义的引用类型相等 操作员需要一个 以下:

(1) 两个操作数都是一个值 属于已知为引用类型的类型 或文本为空。此外,一个 显式引用转换 存在于任一操作数的类型中 到另一个操作数的类型

(2) 一个操作数是T类型的值 其中T是一个类型参数,而 另一个操作数是文本null。 此外,T不具有该值 类型约束

除非其中一个 条件是真的,一个绑定时间 发生错误


这就解释了你的观察。任何两个接口之间都存在显式引用转换,因为两个不同接口的任何两个实例都可能引用同一个对象。可能有一个类C3同时实现了I1和I2,您可以对同一个C3实例进行引用比较,一个实例转换为I1,另一个实例转换为I2。

对于信息,
=
通常与op_Equality操作符相关联,而不是虚拟Equals(加上引用比较,但您已经介绍了这一点)请注意,您引用的是C#3.0规范,其中包含与此问题相关的打字错误。上面的“隐式”应该改为“显式”。这里有很多好的答案,但你的答案最完全地回答了我的问题。非常感谢。