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?

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

+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 for an example.
@Xenolightning: You mean overload, but yes :)
You caught me! My excuse is that it's early in the morning! :-P
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.

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.