7
var fooRef = new FooRef();
var fooRefEnumerable = Enumerable.Empty<FooRef>();

var fooRefEquality = (fooRef == fooRefEnumerable); //This compiles without any errors

var fooVal = new FooVal();
var fooValEnumerable = Enumerable.Empty<FooVal>();

//Compilation error : Error 1 Operator '==' cannot be applied to operands of type 'FooVal' and 'System.Collections.Generic.IEnumerable<FooVal>'
var fooValEquality = (fooVal == fooValEnumerable); 

public class FooRef { }
public struct FooVal { }   

Why is it comparing a single object and an IEnumerable valid for RefTypes?

Nasmi Sabeer
  • 1,370
  • 9
  • 21

3 Answers3

9

Why is it comparing a single object and an IEnumerable is valid for RefTypes?

Because it's entirely feasible that it will return true:

class CunningFooRef : FooRef, IEnumerable<FooRef>
{
    // Implementation...
}

FooRef fooRef = new CunningFooRef();
IEnumerable<FooRef> fooRefEnumerable = Enumerable.Empty<FooRef>();
Console.WriteLine(fooRef == fooRefEnumerable); // False

fooRefEnumerable = (IEnumerable<FooRef>) fooRef;
Console.WriteLine(fooRef == fooRefEnumerable); // True

Note that this is using the same compile-time types for fooRef and fooRefEnumerable as you're using.

If you seal FooRef, so the compiler knows that it's impossible for a FooRef reference to also be an IEnumerable<FooRef> reference, then you'll get a compile-time error.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    +1 Great answer. As an added extra to this, if you really want to be able to write `struct == object`, you can also override the equality operator in the struct. See [here](http://stackoverflow.com/questions/15199026/comparing-two-structs-using) for an example. – Xenolightning Mar 18 '14 at 18:42
  • @Xenolightning: You mean overload, but yes :) – Jon Skeet Mar 18 '14 at 18:46
  • You caught me! My excuse is that it's early in the morning! :-P – Xenolightning Mar 18 '14 at 19:03
1

The reason you're having that is because fooVal(your struct) is different type than the fooValEnumerable(IEnumerable type). Struct is Value type and you can't compare it to a reference type like that.

SirH
  • 535
  • 2
  • 7
0

The == token is used to represent two different operators, which would in some languages (such as VB) be represented with different tokens. If either of the operand types has a defined overload which is applicable to the other type, then == will represent an overloadable equality operator and use that overload. Otherwise, if both operands are reference types, and it would be possible for them to identify the same (non-null) object, it will represent a reference-equality operator. Note that the semantics of a reference-equality test are well defined for any combination of types; if X identifies an apple and Y identifies an orange, the question "do X and Y identify the same object" can be answered without difficulty (it's always "no"). C# will balk at some such comparisons on the basis that an attempt to compare things that an attempt to ask a question whose answer is always "no" is apt to be a mistake, but if e.g. X is unsealed class Automobile and Y is an IFloatable, the compiler will allow for the possibility that X and Y might both identify the same amphibious vehicle (which derives from Automobile and implements IFloatable. Note that if X were a sealed class [or a structure, which would necessarily be sealed], the compiler would recognize that if X's class doesn't implement IFloatable, X can't identify an object which does.

supercat
  • 77,689
  • 9
  • 166
  • 211