Método GetHashCode con Dictionary y HashSet

Tengo una pregunta sobre cómo funcionan el Dictionary y HashSet en C #. Según tengo entendido, GetHashCode se usa en tablas hash para determinar la unicidad clave.

En la siguiente página de MSDN, dice:

Un código hash es un valor numérico que se utiliza para insertar e identificar un objeto en una colección basada en hash, como la clase Dictionary, la clase Hashtable o un tipo derivado de la clase DictionaryBase.

Enlazar:MSDN Object.GetHashCode

Si ese es el caso, ¿por qué ContainsKey y Contains devuelven false para car2 cuando tiene el mismo código hash que car1? Si mi comprensión es correcta y si lo que dice MSDN es correcto, ¿no deberían ambos ser verdaderos?

class Program
{
    static void Main(string[] args)
    {            
        // Create a Dictionary and HashSet
        Dictionary<Car, int> carDictionary = new Dictionary<Car, int>();
        HashSet<Car> carSet = new HashSet<Car>();

        // Create 3 Cars (2 generic and 1 Civic)
        Car car1 = new Car();
        Car car2 = new Car();
        Car car3 = new Civic();

        // Test hash values
        int test1 = car1.GetHashCode(); // 22008501
        int test2 = car2.GetHashCode(); // 22008501
        int test3 = car3.GetHashCode(); // 12048305


        // Add 1 generic car and 1 Civic to both Dictionary and HashSet
        carDictionary.Add(car1, 1);
        carDictionary.Add(car3, 1);
        carSet.Add(car1);
        carSet.Add(car3);

        // Why are both of these false?
        bool dictTest1 = carDictionary.ContainsKey(car2);  // false
        bool setTest1 = carSet.Contains(car2); // false

        // Testing equality makes sense
        bool testA = car1.Equals(car2); // false
        bool testB = car1.Equals(car3); // false
    }
}

class Car
{
    public override int GetHashCode()
    {
        return 22008501;
    }
}

class Civic : Car
{
    public override int GetHashCode()
    {
        return 12048305;
    }
}

Respuestas a la pregunta(3)

Su respuesta a la pregunta