Igualdad para .NET PropertyInfos

Tengo un código que compara 2 PropertyInfos con Equals (). Si bien esto normalmente parece funcionar, me he encontrado con una situación extraña donde dos objetos de información de propiedad reflejados para la misma propiedad subyacente no son iguales:

PropertyInfo prop1, prop2; // both are public and not static
Console.WriteLine(prop1 == prop2); // false ???
Console.WriteLine(Equals(prop1, prop2)); // false ???
Console.WriteLine(prop1.DeclaringType == prop2.DeclaringType); // true
Console.WriteLine(prop1.ReturnType == prop2.ReturnType); // true
Console.WriteLine(prop1.Name == prop2.Name); // true
Console.WriteLine(prop1.DeclaringType.GetProperties().Contains(prop1)); // true
Console.WriteLine(prop2.DeclaringType.GetProperties().Contains(prop2)); // false ???

Parece que PropertyInfo no implementa realmente Equals (), pero pensé que .NET almacena en caché los miembros reflejados para que siempre se devuelva la misma instancia. Ciertamente ves a.GetType () == b.GetType () todo el tiempo. ¿No es este el caso de PropertyInfos?

Algunas otras notas: -Esta rareza sucedió cuando se ejecutó una prueba NUnit en .NET 4, VS2012, x86 objetivo de compilación -Esto ni siquiera sucede con todas las propiedades que comparamos de esta manera, pero falla constantemente en una propiedad.

¿Alguien puede explicar este comportamiento?

EDITAR: en caso de que alguien esté interesado, aquí está la función de comparación de igualdad que escribí para comparar MemberInfos:

public class MemberEqualityComparer : EqualityComparer<MemberInfo> {
    public override bool Equals(MemberInfo @this, MemberInfo that) {
        if (@this == that) { return true; }
        if (@this == null || that == null) { return false; }

                        // handles everything except for generics
                    if (@this.MetadataToken != that.MetadataToken
                        || !Equals(@this.Module, that.Module)
                        || this.Equals(@this.DeclaringType, that.DeclaringType))
                    {
                        return false;
                    }

                    bool areEqual;
                    switch (@this.MemberType)
                    {
                        // constructors and methods can be generic independent of their types,
                        // so they are equal if they're generic arguments are equal
                        case MemberTypes.Constructor:
                        case MemberTypes.Method:
                            var thisMethod = @this as MethodBase;
                            var thatMethod = that as MethodBase;
                                                areEqual = thisMethod.GetGenericArguments().SequenceEqual(thatMethod.GetGenericArguments(), 
this);
                            break;
                        // properties, events, and fields cannot be generic independent of their types,
                        // so if we've reached this point without bailing out we just return true.
                        case MemberTypes.Property:
                        case MemberTypes.Event:
                        case MemberTypes.Field:
                            areEqual = true;
                            break;
                        // the system guarantees reference equality for types, so if we've reached this point
                        // without returning true the two are not equal
                        case MemberTypes.TypeInfo:
                        case MemberTypes.NestedType:
                            areEqual = false;
                            break;
                        default:
                            throw new NotImplementedException(@this.MemberType.ToString());
    }

    public override int GetHashCode(MemberInfo memberInfo) {
        if (memberInfo == null) { return 0; }

    var hash = @this.MetadataToken 
        ^ @this.Module.GetHashCode() 
        ^ this.GetHashCode(@this.DeclaringType);
    return hash;
    }
}

Respuestas a la pregunta(2)

Su respuesta a la pregunta