Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't the operator '==' be applied to a struct and default(struct)?

I'm seeing some odd behaviour after using FirstOrDefault() on a collection of structs. I've isolated it into this reproduction case. This program won't compile

using System; using System.Linq;  namespace MyProgram {     public class Program {         static void Main() {              var users = new User[] {             new User() { UserGuid = Guid.NewGuid(), Username = "user01" },             new User() { UserGuid = Guid.NewGuid(), Username = "user02" }         };              var user = users.FirstOrDefault(u => u.Username == "user01");             Console.WriteLine(user == default(User) ? "not found" : "found");         }      }      public struct User {         public Guid UserGuid;         public string Username;     } } 

The compiler error is the rather cryptic:

Operator '==' cannot be applied to operands of type 'MyProgram.User' and 'MyProgram.User'

Changing the struct to a class works fine - but I'm at a loss as to why I can't compare a struct 'instance' to a default?

like image 809
Dylan Beattie Avatar asked Nov 15 '13 15:11

Dylan Beattie


People also ask

Can you override a struct?

* Structs have statically-dispatched methods and properties; there's no ability to override.

Does struct have default constructor in C#?

C# does not allow a struct to declare a default, no-parameters, constructor. The reason for this constraint is to do with the fact that, unlike in C++, a C# struct is associated with value-type semantic and a value-type is not required to have a constructor.

Can we equate two structures in C?

Yes if the structure is of the same type.


1 Answers

For classes, the == operator uses reference equality. Of course, structs are value types, so they can't be compared by reference. There is no default implementation of == for structs because memberwise comparison isn't always a valid comparison, depending on the type.

You can instead use the Object.Equals method, which does compare memberwise:

Console.WriteLine(user.Equals(default(User)) ? "not found" : "found"); 

Or you could just implement == to call Object.Equals:

public static bool operator ==(User lhs, User rhs) {     return lhs.Equals(rhs); } 

However, the default implementation of Equals for structs uses reflection, and so is very slow. It would be better to implement Equals yourself, along with == and != (and possibly GetHashCode too):

public override bool Equals(Object obj) {     return obj is User && Equals((User)obj); }  public bool Equals(User other) {     return UserGuid == other.UserGuid && Username == other.Username; }  public static bool operator ==(User lhs, User rhs) {     return lhs.Equals(rhs); }  public static bool operator !=(User lhs, User rhs) {     return !lhs.Equals(rhs); } 
like image 127
Cyanfish Avatar answered Oct 12 '22 06:10

Cyanfish