Every type in C# implements GetHashcode(), Classes, structs, enums, string, int… If you can put a type as a key to a dictionary, it has a GetHashcode() implementation. Internally, thats what Dictionary uses for keys anyway.
if you’re asking about how to implement a GetHashcode() function:
When you make a class override a base class and you override an equals method you are also required by C# to also override GetHashcode(), its a virtual function all types can override. You typically need to determine what values in your class describe an instance’s equality. if you want separate instances to be considered equal then they must compute the same hashcode. However the corollary is not true, It’s allowed for two items not be equal yet have the same hashcode
For Reference types (unless overridden in a base class), base.GetHashcode() basically returns the instance ID for that reference. thus by default if ReferneceEquals(A,B) is true, then it usually means base.GetHashcode() value is the same for both A and B.
If however you want two instances to be considered equal while being different references you need to override both .Equals() and .GetHashcode() methods. equals should just compare the values for the 2 instances, and GetHashcode should discard the base.GetHashcode and perform a factored-sum on the hashcode of all the fields important for the class’s equality.
say for example you have a type thats typically deserialized from an external, remote resource so you’ll often get copies of that type and you need to check if a new copy is different from a local cache
public class NetworkLobbyPlayer
{
public int lobbyId;
public int lobbyIndex;
public Guid playerId;
public override bool Equals(object other)
{
if(other == null) return false;
return this.lobbyId.Equals(other.lobbyId)
&& this.lobbyIndex.Equals(other.lobbyIndex)
&& this.playerId.Equals(other.playerId);
}
public override int GetHashCode()
{
//unchecked protects against integer overflow. if hash gets too large it will wrap
// inside performing a factored sum to reduce paired type collisions
// otherwise {lobbyid:5,lobbyIndex:2} would be considered equal to {lobbyid:2,lobbyIndex:5}
unchecked
{
//usually use prime constants to minimize collisions
int hash = 37;
hash = (137 * hash) + lobbyId.GetHashCode();
hash = (137 * hash) + lobbyIndex.GetHashCode();
hash = (137 * hash) + playerId.GetHashCode();
// Note: if a field is a reference type that can be null I'd do something like this
// hash = (137 * hash) + reference?.GetHashCode()??0;
// or for unity objects
// hash = (137 * hash) + (go?go.GetHashCode():0);
return hash;
}
}
}
Now I can then use this to check if a player changed in a slot and update the UI accordingly. Even if the cache I’m holding is a different instance than the copy I pull from the server, they can equate to the same thing and will appear as the same item if used as a key for a dictionary, so long as they have the same values