简体   繁体   English

如何仅在不破坏现有 Object.Equals() 的情况下检查两个对象的属性是否相等?

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

Basically, GethashCode is different even though they contain the SAME values for the properties... so why is the default to return diff hashcodes?基本上, 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?

Is there a more proper way to make it so I don't break how Object.Equals works for my objects, but am still able to have my own equality checking based on the parameter values?有没有更合适的方法来实现它,这样我就不会破坏 Object.Equals 对我的对象的工作方式,但仍然能够根据参数值进行我自己的相等性检查?

The reason I ask is because I have a service: SynchronizeUsers() which downloads an array of users.我问的原因是因为我有一项服务: SynchronizeUsers() ,它下载一组用户。 Instead of clearing out my cache of users, I'd rather just update the ones that need to be updated, remove the ones that the synch says to, and add the new ones.与其清除我的用户缓存,我宁愿只更新需要更新的用户,删除同步所说的用户,然后添加新用户。 But, I can't just do Object.Equals() on these objects.但是,我不能只对这些对象执行 Object.Equals() 。

Too late to answer, but someone might end up here and I need to know my idea is right or wrong.回答太晚了,但有人可能会在这里结束,我需要知道我的想法是对还是错。 If strictly values are the consideration, then why not make the objects JSON and compare the JSON strings?如果严格考虑值,那么为什么不将对象设为 JSON 并比较 JSON 字符串呢? Like:喜欢:

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

If you have ReSharper installed (it's worth it!) then all you have to do is:如果您安装了 ReSharper(这是值得的!),那么您所要做的就是:

Alt+Insert

With your cursor inside the class.在课堂内使用光标。 A partial class is good for hiding the boilerplate.部分类有利于隐藏样板。

It'll automatically implement an equality check for each property.它将自动为每个属性实现相等性检查。

(Select all properties w/ Ctrl+A, and you can check all w/ Space!) (使用 Ctrl+A 选择所有属性,您可以使用空格检查所有属性!)

Have you tried implementing your own IEqualityComparer?您是否尝试过实现自己的 IEqualityComparer? You can pass this to an .Equals() overload to define your own custom equality logic, as in您可以将其传递给 .Equals() 重载以定义您自己的自定义相等逻辑,如

User A = User B even if they are distinct instances, if properties x, y, z are the same.用户 A = 用户 B,即使它们是不同的实例,如果属性 x、y、z 相同。

See this: MSDN看到这个: MSDN

Edit: I should have written you can instantiate your EqualityComparer and pass two instances to its Equals() method and get a bool.编辑:我应该写你可以实例化你的 EqualityComparer 并将两个实例传递给它的 Equals() 方法并获得一个布尔值。 Basic console app... will show true, false, false.基本控制台应用程序...将显示真、假、假。 Thing is trivial, has the two properties shown.事情是微不足道的,具有所示的两个属性。

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

It is recommended to over-ride GetHashCode() when over-riding GetEquals().建议在覆盖 GetEquals() 时覆盖 GetHashCode()。

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

eg例如

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

Here's a solution that does not require any custom logic in the class and uses generics to ensure both arguments (obj1 and obj2) are the same type at compile time:这是一个不需要类中的任何自定义逻辑并使用泛型来确保两个参数(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;
    }
  }

Usage:用法:

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

Why not write your own Equality method?为什么不编写自己的 Equality 方法? ie, IE,

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

where IsEqualTo is defined within your user class as:其中 IsEqualTo 在您的用户类中定义为:

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

Add a method:添加一个方法:

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

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

If you just want to hash things look into using an extension method, to generate the hash.如果您只想对事物进行散列,请考虑使用扩展方法来生成散列。

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

Then in your code you could do:然后在您的代码中,您可以执行以下操作:

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

This would leave everything intact, and should not break anything else.这将使所有内容完好无损,并且不应破坏其他任何内容。 If you are looking for a way to compare objects, you could do the same using an extension method:如果您正在寻找一种比较对象的方法,您可以使用扩展方法来做同样的事情:

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

Usage would be like:用法如下:

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

The string array is the exclude list for the compare.字符串数组是比较的排除列表。 It uses reflection but the performance is very good.它使用反射但性能非常好。 Please check apache commons lang 3 library请检查 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