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

时间:2010-10-26 05:19:04

标签: 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();

        I1 i1 = c1;
        I2 i2 = c2;

        bool x = c1 == c2;
        bool y = i1 == i2;
    }
}

编译器说我无法比较后面的c1 == c2。这些类型完全不相关。然而,它允许我比较i1 == i2。我希望它在编译时失败时会出错,但我很惊讶地发现你可以将任何接口与任何其他接口进行比较,编译器永远不会抱怨。我可以比较,例如(I1)null == (IDisposable)null,没问题。

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

我错过了什么?

4 个答案:

答案 0 :(得分:13)

我认为这是以这种方式完成的,因为你可以拥有一个继承两个接口的类型,对于这种情况,这种比较可能很有用:

interface I1 {}
interface I2 {}
class C1 : I1, I2 {}

因此,在第一种情况下,编译器肯定知道对象是不同的,但在第二种情况下,它们可能不是。

答案 1 :(得分:12)

首先,请注意Hans正在引用规范的正确部分,但他引用的规范版本中有一个与您的问题相关的拼写错误。纠正的C#4规范说:

  

预定义的引用类型相等   运营商需要其中一个   以下:

     

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

     

(2)一个操作数是T类型的值   其中T是一个类型参数和   其他操作数是文字null。   此外,T没有价值   类型约束。

     

除非其中一个   条件是真的,一个约束时间   发生错误。

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

答案 2 :(得分:4)

在C#语言规范第7.9.6章“引用类型相等运算符”中很好地描述了它:

  

预定义的引用类型相等   运营商是:

     

bool operator ==(object x,object y);   
bool operator!=(对象x,   对象y);

     

运营商返回   比较两个参考的结果   为了平等或不平等。

     

由于   预定义的引用类型相等   运算符接受类型的操作数   对象,它们适用于所有类型   不要声明适用的运营商==   和operator!=成员。反过来,   任何适用的用户定义的相等   运营商有效地隐藏了   预定义的引用类型相等   运营商。

     

预定义参考   类型相等运算符需要其中一个   以下内容:
  •两个操作数都是   引用类型值或文字   空值。此外,标准隐含   转换(第6.3.1节)存在于   类型的任一操作数的类型   另一个操作数    •一个操作数是a   类型T的值,其中T是a   type-parameter和另一个操作数   是文字null。此外T   没有值类型   约束。

     

除非其中一个   条件是真的,编译时   发生错误。值得注意的意义   这些规则是:
  • 它是一个   编译时错误使用   预定义的引用类型相等   运营商比较两个参考   众所周知的是不同的   编译时间。例如,如果   编译时类型的操作数是   两个类类型A和B,如果   既不是A也不是B来源于   另外,那就不可能了   两个操作数引用相同   宾语。因此,操作是   被认为是编译时错误。

最后一段是您收到错误的原因。

答案 3 :(得分:0)

  

我的期望是a ==会导致直接引用比较或调用具体类的虚拟等于。

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