A struct is a value type typically used to encapsulate small groups of related variables. Structs inherit from System.ValueType, which overrides Equals and GetHashCode. The Equals implementation calls Equals on each field and returns true if all fields are equal. When there are no GC references, it avoids reflection and uses memcmp (code). GetHashCode is somewhat more complex. It looks for the first non-static field and returns its hash code. If the type has no non-static fields, it returns the hash code of the type.
The default implementation is generic and works for any value type. The drawback is that it is not performant! These methods are called when you check whether two instances are equal (a == b or a.Equals(b)), or when you use the type as a key in a HashSet<T>, Dictionary<TKey, TValue>, or a similar collection. This means that when T is a struct using the default implementation, performance in these collections can be sub-optimal. A quick benchmark shows how slow Equals and GetHashCode are compared to a custom implementation when used with a HashSet<T>:
Source: https://gist.github.com/meziantou/605934eb7376d9c3cc46af0adad937e6
This illustrates how important it is to override Equals and GetHashCode if you want them to be performant!
#Generate equality members
Instead of writing the Equals and GetHashCode methods yourself, you can generate them. You can also generate operators and implement IEquatable<T>.


This will produce the following code:
C#
internal struct StructWithOverrides : IEquatable<StructWithOverrides>
{
public int Value;
public StructWithOverrides(int value)
{
Value = value;
}
public override bool Equals(object obj)
{
return obj is StructWithOverrides overrides && Equals(overrides);
}
public bool Equals(StructWithOverrides other)
{
return Value == other.Value;
}
public override int GetHashCode()
{
return HashCode.Combine(Value);
}
public static bool operator ==(StructWithOverrides left, StructWithOverrides right)
{
return left.Equals(right);
}
public static bool operator !=(StructWithOverrides left, StructWithOverrides right)
{
return !(left == right);
}
}
It is just a matter of seconds to get a performant struct!
#Detect missing overrides using a Roslyn Analyzer
You can detect missing overrides in your application using a Roslyn analyzer. The free analyzer I've created already includes rules for this: https://github.com/meziantou/Meziantou.Analyzer.
You can install the Visual Studio extension or the NuGet package to analyze your code:

Do you have a question or a suggestion about this post? Contact me!