Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can unrelated c# interface references be compared without compiler error?

Tags:

c#

interface

I was surprised recently to discover that the compiler is apparently not strict about comparing interface references and am wondering why it works this way.

Consider this code:

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;
    }
}

The compiler says that I can't compare c1 == c2, which follows. The types are totally unrelated. Yet, it does permit me to compare i1 == i2. I would expect it to error here with a compile-time failure but I was surprised to find out that you can compare any interface to any other and the compiler will never complain. I could compare, for example (I1)null == (IDisposable)null and no problem.

Are interfaces not objects? Are they a special type of reference? My expectation would be that a == would result in either a straight reference compare or a call into the concrete class's virtual Equals.

What am I missing?

like image 558
scobi Avatar asked Oct 26 '10 05:10

scobi


2 Answers

I suppose this was done in a such way because you can have a type inheriting both interfaces and for this case such comparison could be useful:

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

So in the first case compiler definitely knows that objects are different but in second case they might be not.

like image 172
Andrew Bezzub Avatar answered Sep 20 '22 20:09

Andrew Bezzub


First off, note that Hans is quoting the correct section of the specification, but that the edition of the specification he is quoting has a typo which is relevant to your question. The corrected C# 4 specification says:

The predefined reference type equality operators require one of the following:

(1) Both operands are a value of a type known to be a reference-type or the literal null. Furthermore, an explicit reference conversion exists from the type of either operand to the type of the other operand.

(2) One operand is a value of type T where T is a type-parameter and the other operand is the literal null. Furthermore T does not have the value type constraint.

Unless one of these conditions are true, a binding-time error occurs.

This explains your observation. There is an explicit reference conversion between any two interfaces because any two instances of two different interfaces could be referencing the same object. There could be a class C3 which implements both I1 and I2, and you could be doing a reference comparison of the same instance of C3, one converted to I1 and the other converted to I2.

like image 22
Eric Lippert Avatar answered Sep 16 '22 20:09

Eric Lippert