>编辑:
我想做的是找出db.Id
是否等于xml.Id
,db.SubTitle
等于xml.SubTitle
....等。。。。。我所有的道具
我也试过
bool result = db.SequenceEqual(xml)
它始终返回 false。
编辑
在我最终寻求帮助之前,我确实进行了搜索,但我不确定解决我的问题的最佳方法是什么。
我有两个 IList 对象,它们都具有完全相同的属性,但数据可能不同。一个对象从数据库填充,另一个对象从 XML 读取以比较两个源是否同步。
这是我的对象看起来像:
public class EmployeeObject
{
public Int32 Id { get; set; }
public string SubTitle { get; set; }
public string Desc { get; set; }
public bool Active { get; set; }
public string ActiveDateTime { get; set; }
}
这是我尝试过的:
IList<EmployeeObject> db = Db.EmployeeRepository.PopulateFromDb();
IList<EmployeeObject> xml = Xml.EmployeeRepository.PopulateFromXml();
到目前为止,两个对象都填充了数据,一切顺利....
现在是时候比较了:
我尝试过这样的事情:
if ((object)xml == null || ((object)db) == null)
return Object.Equals(xml, db);
return xml.Equals(db); // returning false all the time
我已经检查了两个对象具有完全相同的数据,但仍返回false
您使用的Equals
方法将确定两个引用是否引用同一列表,而不是内容是否相同。 您可以使用SequenceEqual
来实际验证两个序列是否具有相同顺序的相同项目。
接下来,您将遇到一个问题,即列表中的每个项目将被比较,以查看它们是否引用相同的对象,而不是包含相同的字段值或相同的 ID 值,这似乎是您想要的。 一种选择是自定义比较器,但另一种选择是提取有问题的"标识"对象:
bool areEqual = db.Select(item => item.id)
.SequenceEqual(xml.Select(item => item.id));
你应该像这样覆盖类中的Equals
和GetHashCode
:
public class EmployeeObject {
public Int32 Id { get; set; }
public string SubTitle { get; set; }
public string Desc { get; set; }
public bool Active { get; set; }
public string ActiveDateTime { get; set; }
public override bool Equals(object o){
EmployeeObject e = o as EmployeeObject;
if(e == null) return false;
return Id == e.Id && SubTitle == e.SubTitle && Desc == e.Desc
&& Active == e.Active && ActiveDateTime == e.ActiveDateTime;
}
public override int GetHashCode(){
return Id.GetHashCode() ^ SubTitle.GetHashCode() ^ Desc.GetHashCode()
^ Active.GetHashCode() ^ ActiveDateTime.GetHashCode();
}
}
然后使用 SequenceEqual
方法:
return db.OrderBy(e=>e.Id).SequenceEqual(xml.OrderBy(e=>e.Id));
IList
没有Equals
方法。 你调用的是标准的 Object 等于,它检查两个变量是否指向同一个对象。
如果要检查列表在语义上是否等效,则需要检查列表中的每个对象是否等效。 如果 EmployeeObject
类具有适当的 Equals
方法,则可以使用 SequenceEquals
来比较列表。
您可以实现IEqualityComparer并使用采用IEqualityComparer的SequenceEquals重载。下面是来自 msdn 的 IEqualityComparer 的示例代码:
class BoxEqualityComparer : IEqualityComparer<Box>
{
public bool Equals(Box b1, Box b2)
{
if (b1.Height == b2.Height && b1.Length == b2.Length && b1.Width == b2.Width)
{
return true;
}
else
{
return false;
}
}
public int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
}
然后,您可以像这样使用 SequenceEquals:
if (db.SequnceEquals(xml), new MyEqualityComparer())
{ /* Logic here */ }
请注意,仅当项目在列表中也按相同顺序排序时,这将返回 true。如果合适,您可以预订这样的商品:
if (db.OrderBy(item => item.id).SequnceEquals(xml.OrderBy(item => item.id)), new MyEqualityComparer())
{ /* Logic here */ }
显然,如果您比较两个不同的列表,return xml.Equals(db);
的返回将始终false
。
要使这有意义,唯一的方法是让您实际上更具体地说明这两个列表相等意味着什么。也就是说,您需要浏览两个列表中的元素,并确保列表都包含相同的项目。即使这样也是模棱两可的,但假设您的元素为 Equals()
和 GetHashCode()
提供了适当的覆盖,那么您可以继续实现实际的列表比较。
通常,比较两个不包含重复项的列表的最有效方法是使用由其中一个列表的元素构造的哈希集,然后循环访问第二个列表的元素,测试是否在哈希集中找到每个元素。
如果列表包含重复项,最好的办法是将它们都排序,然后同时浏览列表,确保每个点的元素匹配。
SequenceEqual
,前提是您实际上可以比较EmployeeObject
的实例。 您可能需要Equals
EmployeeObject
:
public override bool Equals(object o)
{
EmployeeObject obj = o as EmployeeObject;
if(obj == null) return false;
// Return true if all the properties match
return (Id == obj.Id &&
SubTitle == obj.SubTitle &&
Desc == obj.Desc &&
Active == obj.Active &&
ActiveDateTime == obj.ActiveDateTime);
}
然后你可以做:
var same = db.SequenceEqual(xml);
您还可以传入一个实现IEqualityComparer
的类,该类指示SequenceEqual
如何比较每个实例:
var same = db.SequenceEqual(xml, someComparer);
另一种快速的方法(虽然没有那么快)是构建要比较的值的两个枚举,可能是您案例中的id
属性:
var ids1 = db.Select(i => i.Id); // List of all Ids in db
var ids2 = xml.Select(i => i.Id); // List of all Ids in xml
var same = ids1.SequenceEqual(ids2); // Both lists are the same