2012-11-28 8 views
6

2つのPropertyInfosとEquals()を比較するコードがあります。.NET Equality for 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が実際に等号を実装する()が、私はありませんように見えます:これは正常に動作しているようですが、私は2つが同じ基本プロパティのプロパティ情報オブジェクトが等しくない反映奇妙な状況に遭遇してきました.NETキャッシュはメンバを反映し、常に同じインスタンスが返されると考えました。あなたは確かに常にa.GetType()== b.GetType()を参照してください。これはPropertyInfosの場合ですか?

他のいくつかの注意事項:.NET 4、VS2012でNUnitのテストを実行するときに - このすごみは - これも、私たちがこのように比較し、すべてのプロパティに対して発生しませんが、それは1に一貫失敗し、x86のビルドターゲットが起こりましたプロパティ。

誰でもこの動作を説明できますか?

編集:私は、彼らが異なるReflectedTypeを持って推測している

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

あなたはdecompiledコードを見たことがありますか? – pylover

+0

@smartcaveman、宣言している型が等しい場合は常にfalseを返すつもりでしたか?私はそこに「ない」とすべきだと思う。また、Equalsメソッドの最後の数行は途切れているように見えます。なぜなら、return文や閉じブレースがないからです。 – Jax

答えて

5

:ケースの誰もが興味を持っている中で、ここで私はMemberInfosを比較するために書いたEqualityComparison機能です。たとえば、継承:

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

は今typeof(A).GetProperty("Foo")typeof(B).GetProperty("Foo")を見てください。

12

オブジェクトIDはTypeクラスに対してのみ提供され、他のリフレクションクラスに対しては保証されません。 A 同等性を比較する健全な方法は、プロパティに同じメタデータトークンがあり、同じモジュールから来ていることを確認することです。したがって、これを試してください:

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

これは、ecma 335が適用される限り意味があります。あなたが投稿していないので、あなたのコードに対してこれをテストすることはできませんでした。だからそれを試してみてください。

+0

これは、ジェネリック型のプロパティを除いて動作しているようです(List .Count == List .Countを使用しない限り)。 – ChaseMedallion

+1

@ChaseMedallion、 'prop1.DeclaringType == prop2.DeclaringType'との併用を追加するのはどうですか?そのようなケースをカバーすると思われます。 – smartcaveman

+0

@smartcaveman:DeclaringTypeはプロパティジェネリックを扱います。なぜなら、プロパティそのものはジェネリックではない(宣言するタイプのみ)ことができるからです。ただし、このメソッドをすべてのメンバーに拡張するには、ジェネリックメソッドを処理するための追加のチェックを行う必要があります。任意メンバーの(一見)完全なチェックセットについては、私の投稿コード(質問内)を参照してください。上に向かってDeclaringTypeチェックが表示されます。 – ChaseMedallion