c#比较两个对象模型中的数据

我有一个对话框,当它产生时,它会被对象模型中的数据填充。 此时,数据被复制并存储在“备份”对象模型中。 当用户完成更改并单击“确定”关闭对话框时,我需要一种快速方法来比较备份对象模型和实时模型 – 如果有任何更改,我可以为用户创建一个新的撤消状态。

如果可能的话,我不想为对象模型中的每个类编写比较函数。

如果我序列化了两个对象模型并且它们相同但存储在不同的内存位置它们是否相等? 是否存在比较两个序列化对象模型的简单方法?

我没有打扰哈希字符串,但只是一个直接的二进制序列化工作奇迹。 当对话框打开时序列化对象模型。

BinaryFormatter formatter = new BinaryFormatter(); m_backupStream = new MemoryStream(); formatter.Serialize(m_backupStream,m_objectModel); 

然后,如果用户使用可用控件(或不是)添加到对象模型。 当对话框关闭时,您可以使用新的序列化与原始序列化进行比较 – 这对我来说是我如何决定是否需要撤消状态。

 BinaryFormatter formatter = new BinaryFormatter(); MemoryStream liveStream = new MemoryStream(); formatter.Serialize(liveStream,m_objectModel); byte[] streamOneBytes = liveStream.ToArray(); byte[] streamTwoBytes = m_backupStream.ToArray(); if(!CompareArrays(streamOneBytes, streamTwoBytes)) AddUndoState(); 

并且比较数组函数可以满足任何人的需要 – 不是比较两个数组的最佳方法。

 private bool CompareArrays(byte[] a, byte[] b) { if (a.Length != b.Length) return false; for (int i = 0; i < a.Length;i++) { if (a[i] != b[i]) return false; } return true; } 

我想说最好的方法是在你的模型中的所有类上实现相等运算符(如果你要进行比较,这通常是一个好主意)。

 class Book { public string Title { get; set; } public string Author { get; set; } public ICollection Chapters { get; set; } public bool Equals(Book other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Equals(other.Title, Title) && Equals(other.Author, Author) && Equals(other.Chapters, Chapters); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != typeof (Book)) return false; return Equals((Book) obj); } public override int GetHashCode() { unchecked { int result = (Title != null ? Title.GetHashCode() : 0); result = (result*397) ^ (Author != null ? Author.GetHashCode() : 0); result = (result*397) ^ (Chapters != null ? Chapters.GetHashCode() : 0); return result; } } } 

此片段由ReSharper自动生成,但您可以将其作为基础。 基本上,您必须使用自定义比较逻辑扩展非重写Equals方法。

例如,您可能希望使用Linq扩展中的SequenceEquals来检查章节集合是否按顺序相同。

比较两本书现在就像说:

 Book book1 = new Book(); Book book2 = new Book(); book1.Title = "A book!"; book2.Title = "A book!"; bool equality = book1.Equals(book2); // returns true book2.Title = "A different Title"; equality = book1.Equals(book2); // returns false 

请记住,还有另一种实现相等的方法: System.IEquatable ,它由System.Collections命名空间中的各个类用于确定相等性。

我会说检查一下,你就行了!

我理解你的问题是如何在没有类型的先验知识的情况下比较两个对象的值相等(而不是引用相等),例如,如果它们实现IEquatable或覆盖Equals。

为此,我建议两个选项:

A.使用通用序列化类来序列化两个对象并比较它们的值。 例如,我有一个名为XmlSerializer的类,它接受任何对象并将其公共属性序列化为XML文档。 在这个意义上,具有相同值和可能相同引用的两个对象将具有相同的值。

B.使用reflection,比较两个对象的所有属性的值,例如:

 bool Equal(object a, object b) { // They're both null. if (a == null && b == null) return true; // One is null, so they can't be the same. if (a == null || b == null) return false; // How can they be the same if they're different types? if (a.GetType() != b.GetType()) return false; var Props = a.GetType().GetProperties(); foreach(var Prop in Props) { // See notes * var aPropValue = Prop.GetValue(a) ?? string.Empty; var bPropValue = Prop.GetValue(b) ?? string.Empty; if(aPropValue.ToString() != bPropValue.ToString()) return false; } return true; } 

这里我们假设我们可以轻松地比较属性,例如它们是否都实现IConvertible,或者正确覆盖ToString。 如果不是这种情况,我会检查它们是否实现IConvertible,如果不是,则递归调用属性上的Equal()。

这仅适用于比较公共属性的内容。 当然,您也可以检查私有和受保护的字段和属性,但如果您对这些对象知之甚少,那么您可能会遇到麻烦,但这样做。