2012-11-28 36 views
6

我有一些比較2 PropertyInfos和Equals()的代碼。雖然這通常似乎工作,我已經運行到哪裏了相同的底層等兩項反映房地產信息對象一個奇怪的現象是不相等的:.NET PropertyInfos的平等

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

它看起來像的PropertyInfo實際上並沒有實現equals(),但我認爲.NET緩存反映了成員,以便始終返回相同的實例。你一定會一直看到a.GetType()== b.GetType()。 PropertyInfos不是這種情況嗎?

其他一些注意事項: - 這個古怪的.NET 4運行NUnit測試時發生的,VS2012,x86版本的目標 - 這甚至不發生,因爲我們這樣比較的所有屬性,但它在一個一致的失敗屬性。

任何人都可以解釋這種行爲嗎?

編輯:如果有人有興趣,這裏是EqualityComparison功能我寫的比較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; 
    } 
} 
+0

你見過反編譯的代碼嗎? – pylover

+0

@smartcaveman,只要聲明類型相同,你是否打算返回false?我認爲那裏應該有一個「不」。另外,您的Equals方法的最後幾行似乎被切斷,因爲沒有返回語句或關閉大括號。 – Jax

回答

5

我猜測他們有不同的ReflectedType。例如,繼承:

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

現在看typeof(A).GetProperty("Foo")typeof(B).GetProperty("Foo")

12

對象標識只承諾Type類,不承認其他反射類。 A 可能的聲音比較的方法是檢查屬性是否具有相同的元數據標記並來自同一個模塊。所以試試這個:

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

只要ecma 335適用,這是有道理的。我無法對您的代碼進行測試,因爲您沒有發佈它。所以試試吧。

+0

這似乎工作,除了泛型類型的屬性(除非你想列表。計數==列表。計數)。 – ChaseMedallion

+1

@ChaseMedallion,如何通過'prop1.DeclaringType == prop2.DeclaringType'添加一個連詞?似乎將涵蓋這種情況 – smartcaveman

+0

@smartcaveman:DeclaringType很好地處理屬性泛型,因爲屬性本​​身不能是泛型的(只是聲明類型)。但是,要將此方法擴展到所有成員,您需要執行一些額外的檢查來處理泛型方法。查看我發佈的代碼(在問題中)查看任意成員的(看似)完整檢查集。您會注意到頂部的DeclaringType檢查。 – ChaseMedallion