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

C# 如何在不破坏现有对象的情况下检查两个对象的属性是否相等。Equals()?,c#,object,equals,hashcode,C#,Object,Equals,Hashcode,基本上,GethashCode是不同的,即使它们包含相同的属性值。。。那么,为什么默认返回diff hashcode呢 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.Usern

基本上,GethashCode是不同的,即使它们包含相同的属性值。。。那么,为什么默认返回diff hashcode呢

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?
公共类用户
{
公共Int32 Id{get;set;}
公共字符串用户名{get;set;}
}
用户a=新用户();
a、 Id=1;
a、 用户名=“你好”;
用户b=新用户();
b、 Id=1;
b、 用户名=“你好”;
WriteLine(“Hash A:{0}| Hash B:{1}”,A.GetHashCode(),B.GetHashCode());

//散列A:37121646 |散列B:45592480您是否尝试实现自己的IEqualityComparer?您可以将其传递给.Equals()重载以定义自己的自定义相等逻辑,如中所示

用户A=用户B,即使它们是不同的实例,如果属性x、y、z相同

见此:

编辑:我应该已经写了,你可以实例化你的EqualityComparer,并将两个实例传递给它的Equals()方法,然后得到一个bool。基本控制台应用程序。。。会显示真、假、假。事物是平凡的,有两个属性显示

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();
    }
}
var comparer=newthingqualitycomparer();
WriteLine(comparer.Equals(newthing(){Id=1,Name=“1”},newthing(){Id=1,Name=“1”}));
WriteLine(comparer.Equals(newthing(){Id=1,Name=“1”},newthing(){Id=2,Name=“2”}));
WriteLine(comparer.Equals(newthing(){Id=1,Name=“1”},null));
类别ThingQualityComparer:IEqualityComparer
{
公共布尔等于(事物x,事物y)
{
如果(x==null | | y==null)
返回false;
返回(x.Id==y.Id&&x.Name==y.Name);
}
public int GetHashCode(对象对象)
{
返回obj.GetHashCode();
}
}

当超越GetEquals()时,建议超越GetHashCode()

e、 g


为什么不写你自己的平等方法呢?即

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

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

Alt+Insert
将光标放在类中。分部类用于隐藏样板文件

它将自动为每个属性执行相等检查


(选择所有属性w/Ctrl+A,您可以选中所有w/Space!)

字符串数组是用于比较的排除列表。它使用反射,但性能非常好。请检查apache commons lang 3库

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

下面是一个解决方案,它不需要类中的任何自定义逻辑,并使用泛型来确保两个参数(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;
    }
  }

来不及回答,但有人可能会来这里,我需要知道我的想法是对的还是错的。 如果考虑严格的值,那么为什么不将对象设置为JSON并比较JSON字符串呢?比如:

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

哈希代码在应用程序运行期间发生变化是正常的。不正常的是
a.GetHashCode()!=b、 GetHashCode()
——编写该类的人使其出错,除非该类具有自动初始化为非固定值的重要成员(例如,
DateTime.Now
)。此外,这里的问题是什么?(a) 如何使
Equals
返回true,或者(b)与
GetHashCode
相关的内容?-1:这是一个糟糕的想法,因为它没有考虑
Equals
GetHashCode
之间的关系。而且,只有在您可以修改类的情况下,它才能工作。为什么它需要考虑
GetHashCode()
?我错过什么了吗<当
a
b
是单独的对象实例IIRC时,code>a.GetHashCode()==b.GetHashCode()
始终为false。@flyingstrudel:这不正确。合同规定,当两个对象比较相等时,它们的哈希代码也必须相等。您的解决方案会更改相等比较的结果,但不会确保当它返回
true
时,哈希代码也将相等。[旁白:
a
b
是独立的对象实例,这完全不能告诉我们它们的hashcode]@Jon-他使用的是数组,不是散列,但这是真的。[旁白:如果你不实现你自己的
GetHashCode()
我不认为它一定是相等的,除非它们是同一个实例]@flyingstrudel:我在代码中没有看到任何数组。此外,文档()也同意我的观点:“如果两个对象的比较结果相等,则每个对象的GetHashCode方法必须返回相同的值。但是,如果两个对象的比较结果不相等,则两个对象的GetHashCode方法不必返回不同的值。”+1这是一种有效的方法,但它确实引入了很多不必要的代码。您是对的,它引入了更多的代码,但正如ebyrob的评论所指出的,最佳实践是无论如何重写GetHashCode(),而IEqualityComparer只有两个方法Equals()和GetHashCode()可以重写。就我个人而言,我更喜欢将这种“业务逻辑”分开;一个单独的比较器也适用于国际奥委会。。。但最终重写Equals()也会很好。@Nix:如果需要这段代码来实现应用程序的业务逻辑,那么我认为这是最必要的。@Jon同意,但这不是唯一的方法,这种方法比简单地使用扩展使用更多的代码。当数据集有一个明显的相等比较时,为什么要为一个还没有自己默认相等比较的类添加自定义IEqualityComparer?我刚刚发布了一个ReSharper如何自动完成这项工作的答案,仅供参考。:-)最好的答案,因为它允许代码有dynam
  var c1 = new ConcreteType { Foo = "test1" };
  var c2 = new ConcreteType { Foo = "test1" };
  var areEqual = ObjectComparerUtility.ObjectsAreEqual(c1, c2);
  Assert.IsTrue(areEqual);
if (JsonConvert.SerializeObject(obj1) == JsonConvert.SerializeObject(obj2)) continue;