我有以下两个清单:
List<MyObject> oldList = new List<MyObject>();
oldList.Add(new MyObject { Id = 1, Name = "hello" });
oldList.Add(New MyObject { Id = 2, Name = "world" });
List<MyObject> newList = new List<MyObject>();
newList.Add(new MyObject { Id = 1, Name = "Hello" });
newList.Add(new MyObject { Id = 3, Name = "World" });
newList.Add(new MyObject { Id = 4, Name = "hello" });
我想写一些东西来比较两个列表,如果列表不同,则返回布尔值。
例如,上述列表在以下方面有所不同:
我尝试了以下内容:
if (oldList != newList)
和
if (!oldList.SequenceEqual(newList))
但是,两者都会产生不准确的结果。我知道我可以创建一个类IEqualityComparer
的类来实现HashSet
比较;但是我也读到它可能对我的情况不起作用......有人可以说明如何比较两个对象来检测我指定的变化类型吗?
答案 0 :(得分:1)
正如您所说,您只需在IEquatable<MyObject>
中实施正确的MyObject
界面,或实施IEqualityComparer<MyObject>
/// <summary>
/// Fully equatable MyObject
/// </summary>
public class MyObject : IEquatable<MyObject>
{
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return false;
}
MyObject other = obj as MyObject;
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
public bool Equals(MyObject other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
private bool InnerEquals(MyObject other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return true;
}
return this.Id == other.Id && this.Name == other.Name;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.Id.GetHashCode();
hash = hash * 23 + (this.Name != null ? this.Name.GetHashCode() : 0);
return hash;
}
}
}
然后你可以使用
if (!oldList.SequenceEqual(newList))
请注意,此将比较元素顺序!如果更改元素顺序,则比较将返回false
或者您可以使用&#34;外部&#34; IEqualityComparer<MyObject>
public class MyObjectEqualityComparer : IEqualityComparer<MyObject>
{
public static readonly MyObjectEqualityComparer Default = new MyObjectEqualityComparer();
protected MyObjectEqualityComparer()
{
}
public bool Equals(MyObject x, MyObject y)
{
if (object.ReferenceEquals(x, null))
{
return object.ReferenceEquals(y, null);
}
if (object.ReferenceEquals(y, null))
{
return false;
}
// Here we know that x != null && y != null;
if (object.ReferenceEquals(x, y))
{
return true;
}
return x.Id == y.Id && x.Name == y.Name;
}
public int GetHashCode(MyObject obj)
{
if (obj == null)
{
return 0;
}
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + obj.Id.GetHashCode();
hash = hash * 23 + (obj.Name != null ? obj.Name.GetHashCode() : 0);
return hash;
}
}
}
像
一样使用它if (!oldList.SequenceEqual(newList, MyObjectEqualityComparer.Default))
请注意,关于如何编写相等比较器有各种各样的思想,并且有一点需要注意:如果你覆盖operator==
,你必须非常警惕不在比较器中使用它: - )
operator==
重载时错误代码的典型示例
public bool Equals(MyObject other)
{
// BOOOM!!! StackOverflowException!
// Equals will call operator== that will probably call
// Equals back! and so on and so on.
if (other == null)
{
return false;
}
return this.InnerEquals(other);
}
所以最好做object.ReferenceEquals(something, someotherthing)
做参考比较。
然后有null
处理属性的问题:
Name
(a string
)的哈希值如下:
hash = hash * 23 + obj.Name != null ? obj.Name.GetHashCode() : 0
因此如果obj.Name
为null
,则代码不会在NullReferenceException
中进行展示。匿名对象的自动生成代码使用另一种方式:
hash = hash * 23 + EqualityComparer<string>.Default.GetHashCode(obj.Name);
EqualityComparer<string>.Default
即使使用null
值也可以安全使用。
对于Equals
属性的比较,匿名对象的自动生成代码使用了另一个有趣的技巧:
&& EqualityComparer<string>.Default.Equals(this.Name, obj.Name);
所以它使用EqualityComparer<string>.Default.Equals
,然后正确使用各种方法/接口来比较对象。