Often when you create a class you need to override the the GetHashCode method, to easily compare instances using a custom Equals operator or to use the class as a key in dictionaries etc. I've seen various ways of doing this, but they are usually either wrong, slow, complex or difficult to remember (things like string concatenation, bit shifting, xor, using prime numbers etc.) As ever with programming, if there is a complex problem to solve then somebody has probably already solved it (and I don't mean copy/pasting GetHashCode algorithms from stack overflow!). One place this has already been done within the .NET framework is the Tuple type. The algorithm is fast, we don't need to understand it's complexity and given that it in the framework we can assume it's well tested. So my new favourite way of implementing GetHashCode is to simply project the fields into a Tuple!
public class Example
{
  private string someField1;
  private int someField2;

  public override int GetHashCode()
  {
      return (someField1, someField2).GetHashCode();
  }
}
This isn't quite so straightforward when one of your fields is a collection type, however it can be worked around using IStructuralEquatable as per this MSDN link: https://docs.microsoft.com/en-us/dotnet/api/system.collections.istructuralequatable?redirectedfrom=MSDN&view=netcore-2.2#remarks So as long as your collection types are backed by an Array, you can use the following syntax to generate your hash code based on the array values:
public class Example
{
  private string someField;
  private int[] someArrayField;

  public override int GetHashCode()
  {
      return ((someField, someArrayField) as IStructuralEquatable).GetHashCode(StructuralComparisons.StructuralEqualityComparer);
  }
}