Why can't the operator '==' be applied to a struct and default(struct)?
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);
}
You just have to implement it:
public static bool operator == (User u1, User u2)
{
return u1.Equals(u2); // use ValueType.Equals() which compares field-by-field.
}
In C#, the ==
token is used to represent two different operators (not all languages use the same token for the two operators; VB.NET uses the tokens =
and Is
). One of the operators is an overloadable equality test, and is only usable in cases where either an overload is defined for both operand types, or an overload is defined for one operand type and a type to which the other operand is implicitly convertible. The other operator represents a reference-equality test, and is usable in cases where the equality-test operator would be unusable, and where one operand is a class type which derives from the other, one operand is a class type and the other is an interface type, or both operands are interface types.
The first equality-test operator cannot be used with any type (class, interface, or struct) that does not provide an explicit override for it. If the ==
token is used in cases where the first equality-test operator is not usable, however, C# will try to use the second operator [note that other languages like VB.NET would not do this; in VB.NET, an attempt to to use =
to compare two things that don't define an equality-test overload will be an error, even if the things could be compared using the Is
operator]. That second operator may be used to compare any reference type to another reference of the same type, but is not usable with structures. Since neither type of equality operator is defined for structures, the comparison is disallowed.
If one is wondering why ==
doesn't simply fall back upon Equals(Object)
, which is usable with all types, the reason is that both operands of ==
are subject to type coercion in ways that would prevent its behavior from matching Equals
. For example, 1.0f==1.0, and 1.0==1.0f, both cast the float
operand to double
, but given an expression like (1.0f).Equals(1.0)
the first operand can't be evaluated as anything but float
. Further, if ==
were mapped to Equals
, then it would have been necessary for C# to use a different token to represent a reference-equality test [something the language should have done anyway, but apparently didn't want to do].