When choosing the classes for TPrimaryKey, consider that the
method GetHashCode() should return an integer value that is appropriate for
storage in a collection. Additionally, you may want to use the IEquatable<T>
interface to assist you with equality checks. You may not have a class for
TValue that exposes the TPrimaryKey value. That is ok - it just limits some of
your options for operations like the Remove method. Of course, Remove is a
virtual method so you may provide your own implementation there.