Equality for .NET PropertyInfos

I have code that compares 2 PropertyInfos with Equals (). Although this usually works, I came across a strange situation when two objects of information about objects with reflection for the same basic property are not equal:

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 ??? 

It seems that PropertyInfo does not actually implement Equals (), but I thought .NET caches the reflected elements, so the same instance always returns. You will definitely see a.GetType () == b.GetType () all the time. Does this apply to PropertyInfos?

Some other notes: -This oddity occurred when running the NUnit test in .NET 4, VS2012, x86 build target -This does not happen even with all the properties that we compare in this way, but fail in sequence on the same property.

Can anyone explain this behavior?

EDIT: in case anyone is interested, here is the EqualityComparison function that I wrote to compare 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; } } 
+7
source share
2 answers

I guess they have another ReflectedType . For example, inheritance:

 class A { public int Foo {get;set;} } class B : A {} 

Now look at typeof(A).GetProperty("Foo") and typeof(B).GetProperty("Foo") .

+6
source

Object identification is declared only for the Type class, and not for other reflection classes. Probably a reasonable comparison method for equality is to verify that the properties have the same metadata token and come from the same module. So try the following:

 bool equal = prop1.MetadataToken == prop2.MetadataToken && prop1.Module.Equals(prop2.Module); 

This makes sense as long as ecma 335 is applied. I could not test this against your code since you did not publish it. So just try it.

+12
source

All Articles