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?
* Structs have statically-dispatched methods and properties; there's no ability to override.
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.
Yes if the structure is of the same type.
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); }
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