I have a simple class:
public class TileName {
int Zoom, X, Y;
public override bool Equals (object obj)
{
var o = obj as TileName;
Neither of the implementations in your question are ideal. For example, they'll return exactly the same hash for { Zoom=1, X=2, Y=3 }, { Zoom=2, X=3, Y=1 }, { Zoom=3, X=1, Y=2 } etc etc.
I usually use something like this:
public override int GetHashCode()
{
// 269 and 47 are primes
int hash = 269;
hash = (hash * 47) + Zoom.GetHashCode();
hash = (hash * 47) + X.GetHashCode();
hash = (hash * 47) + Y.GetHashCode();
return hash;
}
(From memory, I think the C# compiler uses something similar when it generates the GetHashCode methods for anonymous types.)