Consider the following types:
class A { }
class B { }
interface IC { }
A a = null; // the value doesn't matter - null or anything else, for all three
B b = null;
IC c = null;
The following does not compile:
var x = a == b;
But the following does compile (as I was surprised to discover):
var x = a == c;
As I understand the compiler falls back to using the default == operator, which is defined on object and thus accepts any type for its arguments. The IL looks like this (ignore the details of ldfld
):
ldarg.0
ldfld class A a
ldarg.0
ldfld class IC c
ceq
stloc.0
In other words it uses reference equality.
My questions:
In terms of language design, why does this make sense? To me it doesn't, and I consider it a big pitfall.
If this is indeed a pitfall, shouldn't Code Analysis warn us about it? (nope - it doesn't). By the way, ReSharper seems to have this feature.
The reason that the second line compiles is that there may be another class that derives from A and implements IC.
public class D : A, IC {}
...
a = new D(); c = a; var t = a == c; //t = true;
Classes can only inherit from one class, so you can never create a class that inherits from both A and B unless A is a descendent of B or vice-versa.
The reason that the a == b
test does not compile is because the compiler has enough information to know that the test cannot possibly be ever true
as the two classes are not in the same hierarchy. Therefore it's the equivalent of the compiler not allowing you to write a condition that is in reality a constant by mistake.
For the interface comparison the compiler sees that there is an operator==(object, object)
that it can use, and since both A
and IC
are implicitly convertible to object
that's what in fact must happen. There can very well be another type (not even necessarily a reference type) that implements IC
so the condition is genuine.
The R# warning is one I appreciate; as the page says, equality comparison between interface types is in some cases somewhat dubious and there an extremely descriptive, simple to replace with solution: object.ReferenceEquals
. Of course there is the counter-argument that the equality operator may have been overloaded so the test might be meaningful. Or it can simply be someone writing in a more terse style. Obviously though banning such use in the compiler is somewhat heavy-handed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With