簡體   English   中英

如何僅在不破壞現有 Object.Equals() 的情況下檢查兩個對象的屬性是否相等?

[英]How do I check if two Objects are equal in terms of their properties only without breaking the existing Object.Equals()?

基本上, GethashCode 是不同的,即使它們包含相同的屬性值......那么為什么默認返回差異哈希碼?

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() 。

回答太晚了,但有人可能會在這里結束,我需要知道我的想法是對還是錯。 如果嚴格考慮值,那么為什么不將對象設為 JSON 並比較 JSON 字符串呢? 喜歡:

if (JsonConvert.SerializeObject(obj1) == JsonConvert.SerializeObject(obj2)) continue;

如果您安裝了 ReSharper(這是值得的!),那么您所要做的就是:

Alt+Insert

在課堂內使用光標。 部分類有利於隱藏樣板。

它將自動為每個屬性實現相等性檢查。

(使用 Ctrl+A 選擇所有屬性,您可以使用空格檢查所有屬性!)

您是否嘗試過實現自己的 IEqualityComparer? 您可以將其傳遞給 .Equals() 重載以定義您自己的自定義相等邏輯,如

用戶 A = 用戶 B,即使它們是不同的實例,如果屬性 x、y、z 相同。

看到這個: MSDN

編輯:我應該寫你可以實例化你的 EqualityComparer 並將兩個實例傳遞給它的 Equals() 方法並獲得一個布爾值。 基本控制台應用程序...將顯示真、假、假。 事情是微不足道的,具有所示的兩個屬性。

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();
    }
}

建議在覆蓋 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;
}

這是一個不需要類中的任何自定義邏輯並使用泛型來確保兩個參數(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);

為什么不編寫自己的 Equality 方法? IE,

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);
}

添加一個方法:

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

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

如果您只想對事物進行散列,請考慮使用擴展方法來生成散列。

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.
}

字符串數組是比較的排除列表。 它使用反射但性能非常好。 請檢查 apache commons lang 3 庫

CompareToBuilder.reflectionCompare(arg0, arg1, new String[]{"UID", "uidcount"})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM