web-dev-qa-db-ja.com

既存のObject.Equals()を壊さずに、2つのオブジェクトのプロパティのみが等しいかどうかを確認するにはどうすればよいですか?

基本的に、GethashCodeは、プロパティの同じ値が含まれていても異なります...では、なぜデフォルトでdiffハッシュコードが返されるのでしょうか。

_public class User
{
    public Int32 Id { get; set; }
    public String Username { get; set; }
}

User a = new User();
a.Id = 1;
a.Username = "Hello";

User b = new User();
b.Id = 1;
b.Username = "Hello";

Console.WriteLine("Hash A: {0} | Hash B: {1}", a.GetHashCode(), b.GetHashCode());
//Hash A: 37121646 | Hash B: 45592480 <-- these values change each time I rerun the app?
_

Object.Equalsがオブジェクトに対してどのように機能するかを壊さないようにするためのより適切な方法はありますが、パラメーター値に基づいて独自の等価性チェックを行うことはできますか?

私が尋ねる理由は、私がサービスを持っているからです:SynchronizeUsers()ユーザーの配列をダウンロードします。ユーザーのキャッシュをクリアするのではなく、更新が必要なユーザーを更新し、同期が指示するユーザーを削除して、新しいユーザーを追加したいと思います。しかし、これらのオブジェクトに対してObject.Equals()を実行することはできません。

11
michael

独自のIEqualityComparerを実装してみましたか?これを.Equals()オーバーロードに渡して、次のように独自のカスタム等号ロジックを定義できます。

ユーザーA =ユーザーBは、それらが別個のインスタンスであっても、プロパティx、y、zが同じである場合。

これを参照してください: [〜#〜] msdn [〜#〜]

編集:EqualityComparerをインスタンス化し、2つのインスタンスをそのEquals()メソッドに渡して、ブール値を取得できるように記述しておく必要があります。基本的なコンソールアプリ...はtrue、false、falseを表示します。物事は些細なことであり、2つの特性が示されています。

var comparer = new ThingEqualityComparer();

Console.WriteLine(comparer.Equals(new Thing() { Id = 1, Name = "1" }, new Thing() { Id = 1, Name = "1" }));
Console.WriteLine(comparer.Equals(new Thing() { Id = 1, Name = "1" }, new Thing() { Id = 2, Name = "2" }));
Console.WriteLine(comparer.Equals(new Thing() { Id = 1, Name = "1" }, null));


class ThingEqualityComparer : IEqualityComparer<Thing>
{
    public bool Equals(Thing x, Thing y)
    {
        if (x == null || y == null)
            return false;

        return (x.Id == y.Id && x.Name == y.Name);
    }

    public int GetHashCode(Thing obj)
    {
        return obj.GetHashCode();
    }
}
11
pelazem

ReSharperがインストールされている場合(それだけの価値があります!)、実行する必要があるのは次のとおりです。

Alt+Insert

クラス内にカーソルを置きます。部分クラスは、定型文を非表示にするのに適しています。

各プロパティの等価性チェックを自動的に実装します。

(Ctrl + Aですべてのプロパティを選択すると、スペースですべてをチェックできます!)

10
RJB

GetEquals()をオーバーライドする場合は、GetHashCode()をオーバーライドすることをお勧めします。

http://msdn.Microsoft.com/en-us/library/ms173147%28v=vs.80%29.aspx

例えば.

public override int GetHashCode()
{
    return this.Username.GetHashCode() * this.Id;
}
3
user645280

ハッシュするだけの場合は、拡張メソッドを使用して調べ、ハッシュを生成します。

public static int GenerateHash(this User myUser){
    return myUser.UserName.GetHashCode() ^ ... other properties....
}

次に、コードで次のことができます。

Console.WriteLine("Hash A: {0} | Hash B: {1}", a.GenerateHash(), b.GenerateHash());

これはすべてを無傷のままにし、他のものを壊してはなりません。オブジェクトを比較する方法を探している場合は、拡張メソッドを使用して同じことを行うことができます。

public static int AreEqual(this User myUser, User someOther){
    return myUser.UserName == someOther.UserName && ...  other properties.
}

使用法は次のようになります:

if(a.AreEqual(b)){
    // these are equal have fun.
}
0
Nix

独自のEqualityメソッドを作成してみませんか?すなわち、

User a = new User();
a.Id = 1;
a.Username = "Hello";
User b = new User();
b.Id = 1;
b.Username = "Hello";
a.IsEqualTo(b);

ここで、IsEqualToはユーザークラス内で次のように定義されています。

Public bool IsEqualTo(user compareTo)
{
  return (UserName == compareTo.UserName && Id == compareTo.Id);
}
0

これは、クラスにカスタムロジックを必要とせず、ジェネリックを使用して、コンパイル時に両方の引数(obj1とobj2)が同じタイプであることを確認するソリューションです。

  public static class ObjectComparerUtility
  {
    public static bool ObjectsAreEqual<T>(T obj1, T obj2)
    {
      var obj1Serialized = JsonConvert.SerializeObject(obj1);
      var obj2Serialized = JsonConvert.SerializeObject(obj2);

      return obj1Serialized == obj2Serialized;
    }
  }

使用法:

  var c1 = new ConcreteType { Foo = "test1" };
  var c2 = new ConcreteType { Foo = "test1" };
  var areEqual = ObjectComparerUtility.ObjectsAreEqual(c1, c2);
  Assert.IsTrue(areEqual);
0
Greg R Taylor

メソッドを追加します。

public class User
{
    public int UserID { get; set; }

    public bool IsUser(object obj) 
    {
        return (obj is User && ((User)obj).UserID == this.UserID);
    }
}
0
FlyingStreudel