Often when there is anyone talking about structs, it is recommended that you override Equals
, GetHashCode
, etc.
Is this also necessary if you have a struct
with just a single integer (or any other simple value type)?
Say i.e.:
public struct LolCatId
{
public int Id { get; }
public LolCatId(int id)
{
Id = id;
}
}
When using in HashSets
etc - is there anything that needs to be thought of or will this work perfectly how you expect in all cases performance-wise?
You should better override Equals
and GetHashCode
since default equliaty members for value types are often reflection-based (and that's why can be slow).
And some default Equals
implementations are quite weird, e.g.:
// Wrong Equals optimization demo:
// .Net (4.7) doesn't use reflection here but compare bytes
// and this decision is incorrect in the context
struct MyDemo {
public double x;
}
...
byte[] bits = BitConverter.GetBytes(double.NaN);
bits[1] = 42;
// a holds "standard" NaN
MyDemo a = new MyDemo() { x = double.NaN };
// b holds "modified" NaN
MyDemo b = new MyDemo() { x = BitConverter.ToDouble(bits, 0)};
Console.Write(string.Join(Environment.NewLine,
$"Are structs equal? {(a.Equals(b) ? "Yes" : "No")}",
$"Are fields equal? {(a.x.Equals(b.x) ? "Yes" : "No")}"));
Outcome:
Are structs equal? No
Are fields equal? Yes
For details see
Let's be on the safe side especially when both methods can be easily implemented, e.g. in your case:
public struct LolCatId {
public int Id { get; }
public LolCatId(int id) {
Id = id;
}
public override int GetHashCode() => Id;
public override bool Equals(object obj) =>
obj is LolCatId other ? other.Id == Id : false;
}