我有一个类比较相同对象的2个实例,并生成它们的差异列表.这是通过循环密钥集合并使用已更改内容的列表填充一组其他集合来完成的(这在查看下面的代码后可能更有意义).这有效,并生成一个对象,让我知道在"旧"对象和"新"对象之间添加和删除的确切内容.
我的问题/担忧是......它真的很难看,有很多循环和条件.是否有更好的方法来存储/接近这一点,而不必过分依赖无穷无尽的硬编码条件?
public void DiffSteps() { try { //Confirm that there are 2 populated objects to compare if (NewStep.Id != Guid.Empty && SavedStep.Id != Guid.Empty) { //Find a good way to compare quickly if the objects are exactly the same...hash? //Compare the StepDoc collections: OldDocs = SavedStep.StepDocs; NewDocs = NewStep.StepDocs; Collection docstoDelete = new Collection (); foreach (StepDoc oldDoc in OldDocs) { bool delete = false; foreach (StepDoc newDoc in NewDocs) { if (newDoc.DocId == oldDoc.DocId) { delete = true; } } if (delete) docstoDelete.Add(oldDoc); } foreach (StepDoc doc in docstoDelete) { OldDocs.Remove(doc); NewDocs.Remove(doc); } //Same loop(s) for StepUsers...omitted for brevity //This is a collection of users to delete; it is the collection //of users that has not changed. So, this collection also needs to be checked //to see if the permisssions (or any other future properties) have changed. foreach (StepUser user in userstoDelete) { //Compare the two StepUser oldUser = null; StepUser newUser = null; foreach(StepUser oldie in OldUsers) { if (user.UserId == oldie.UserId) oldUser = oldie; } foreach (StepUser newie in NewUsers) { if (user.UserId == newie.UserId) newUser = newie; } if(oldUser != null && newUser != null) { if (oldUser.Role != newUser.Role) UpdatedRoles.Add(newUser.Name, newUser.Role); } OldUsers.Remove(user); NewUsers.Remove(user); } } } catch(Exception ex) { string errorMessage = String.Format("Error generating diff between Step objects {0} and {1}", NewStep.Id, SavedStep.Id); log.Error(errorMessage,ex); throw; } }
目标框架是3.5.
你在使用.NET 3.5吗?我确信LINQ to Objects会让这很简单.
另一件需要考虑的事情是,如果你有很多具有共同模式的代码,只有一些事情发生变化(例如"我在比较哪个属性?"那么这是一个很好的候选者,可以采用委托代表的通用方法代表那种差异.
编辑:好的,现在我们知道我们可以使用LINQ:
第1步:减少嵌套
首先,我将取出一层嵌套.代替:
if (NewStep.Id != Guid.Empty && SavedStep.Id != Guid.Empty) { // Body }
我会做:
if (NewStep.Id != Guid.Empty && SavedStep.Id != Guid.Empty) { return; } // Body
像这样的早期返回可以使代码更具可读性.
第2步:查找要删除的文档
如果你只需要为Enumerable.Intersect指定一个关键函数,那就更好了.您可以指定相等比较器,但即使使用实用程序库,构建其中一个也很痛苦.呃,好吧.
var oldDocIds = OldDocs.Select(doc => doc.DocId); var newDocIds = NewDocs.Select(doc => doc.DocId); var deletedIds = oldDocIds.Intersect(newDocIds).ToDictionary(x => x); var deletedDocs = oldDocIds.Where(doc => deletedIds.Contains(doc.DocId));
步骤3:删除文档
使用现有的foreach循环,或更改属性.如果您的属性实际上是List
第4步:更新和删除用户
foreach (StepUser deleted in usersToDelete) { // Should use SingleOfDefault here if there should only be one // matching entry in each of NewUsers/OldUsers. The // code below matches your existing loop. StepUser oldUser = OldUsers.LastOrDefault(u => u.UserId == deleted.UserId); StepUser newUser = NewUsers.LastOrDefault(u => u.UserId == deleted.UserId); // Existing code here using oldUser and newUser }
进一步简化操作的一个选项是使用UserId实现IEqualityComparer(和使用DocId的文档实现一个).