C# 比较两个对象的内容是否相等
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/375996/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Compare the content of two objects for equality
提问by Martin
I have two complex (i.e. objects with string, int, double, List and other home made data type) objects of the same type. I would like to compare the content of both of them to ensure that they are identical. Note: The object doesn't implement .Equals (I have no control on that) and doesn't implement IComparable.
我有两个相同类型的复杂(即具有字符串、整数、双精度、列表和其他自制数据类型的对象)对象。我想比较两者的内容以确保它们相同。注意:该对象不实现 .Equals(我无法控制)并且不实现 IComparable。
Is there a generic way (reflection?) to compare the content of the two objects?
有没有通用的方法(反射?)来比较两个对象的内容?
Thanks!
谢谢!
采纳答案by HanClinto
Is there a generic way to compare the content of the two objects?
有没有通用的方法来比较两个对象的内容?
Well yes, but generally that's known as the IComparable interface.
是的,但通常这被称为 IComparable 接口。
If you could descend from the class and create a child that implemented IComparable, that might be ideal.
如果您可以从类中继承并创建一个实现 IComparable 的孩子,那可能是理想的。
回答by Brad Barker
You could simply write a utility method in another class to do the comparison. However, that is assuming the properties of the class in question are publicly accessible. Are they?
您可以简单地在另一个类中编写一个实用程序方法来进行比较。但是,这是假设所讨论的类的属性是可公开访问的。他们是吗?
回答by Marc Gravell
Reflection would be it, but the issue is the contained types - for example, you can't just use Equals
or EqualityComparer<T>
, since the sub-data alsowon't be conveniently comparable if it is a List<T>
etc.
反射就是它,但问题是包含的类型 - 例如,你不能只使用Equals
or EqualityComparer<T>
,因为如果子数据是等,它也不会方便地进行比较List<T>
。
How often do you need to do this? Could you serialize them and compare the serialized value? That might be the most robust option.
您需要多久执行一次此操作?你能序列化它们并比较序列化的值吗?这可能是最可靠的选择。
回答by Jason Hymanson
Well, you could write some logic to compare all of the properties of the two objects to each other. This gets complicated when it is an object graph with complex subtypes, so you will need to determine how close is good enough.
好吧,您可以编写一些逻辑来将两个对象的所有属性相互比较。当它是具有复杂子类型的对象图时,这会变得复杂,因此您需要确定足够接近的程度。
回答by Charlie Martin
You would need a compare method of something else; in C++ you could just write a global function, but I don't think c# allows that, just as Java doesn't.
您将需要其他东西的比较方法;在 C++ 中,您可以只编写一个全局函数,但我认为 c# 不允许这样做,就像 Java 不允许一样。
What I'd do is write a class that implements iComparable, and has a ctor that takes an object of your desired class, and includes your Equals function. Set it up so all it keeps is a reference to the original object, to save mallocations.
Then you can write
我要做的是编写一个实现 iComparable 的类,并有一个 ctor 来获取所需类的对象,并包含您的 Equals 函数。设置它以便它保留的只是对原始对象的引用,以保存错误分配。
然后你可以写
Foo(A).Equals(new Foo(B))
Foo(A).Equals(new Foo(B))
You could instead inherit from the provided class, but that would mean needing to create and track these things.
您可以改为从提供的类继承,但这意味着需要创建和跟踪这些东西。
回答by Greg Finzer
I have created a class to perform a deep compare of .NET Objects. See:
我创建了一个类来执行 .NET 对象的深度比较。看:
回答by Detlef Kroll
GetHashcode works for me.
GetHashcode 对我有用。
I override GetHashcode() in every class with all public relevant properties X-OR-ed e.g.
我在每个类中使用所有公共相关属性 X-OR-ed 覆盖 GetHashcode() 例如
override GetHashCode()
{
return A.GetHashCode() ^ B.GetHashCode ^ C.SafeString().Get..
}
I iterate this through all classes, again X-OR the values. IsModified compares a previously HashValue with the current. Two different objects couldindeed return the same HashValue, with a chance of 1 to 4 billion, but for many purposes this is good enough for me.
我遍历所有类,再次对值进行异或。IsModified 将先前的 HashValue 与当前进行比较。两个不同的对象确实可以返回相同的 HashValue,有 1 到 40 亿的机会,但对于许多目的来说,这对我来说已经足够了。
But I have an even better idea, using a MemoryStream
但我有一个更好的主意,使用 MemoryStream
here is an Extension:
这是一个扩展:
public static bool IsBinaryEqualTo(this object obj, object obj1)
{
using (MemoryStream memStream = new MemoryStream())
{
if (obj == null || obj1 == null)
{
if (obj == null && obj1 == null)
return true;
else
return false;
}
BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, obj);
byte[] b1 = memStream.ToArray();
memStream.SetLength(0);
binaryFormatter.Serialize(memStream, obj1);
byte[] b2 = memStream.ToArray();
if (b1.Length != b2.Length)
return false;
for (int i = 0; i < b1.Length; i++)
{
if (b1[i] != b2[i])
return false;
}
return true;
}
}
回答by Clement-Edwin ALBERT
Serialize the objects to XML string and you can end up doing a string comparison between the 2 objects that are serialized...
将对象序列化为 XML 字符串,您最终可以在序列化的 2 个对象之间进行字符串比较...
private string Serialize<T>(T value)
{
if (value == null)
{
return string.Empty;
}
try
{
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
StringWriter stringWriter = new StringWriter();
XmlWriter writer = XmlWriter.Create(stringWriter);
xmlserializer.Serialize(writer, value);
string serializeXml = stringWriter.ToString();
writer.Close();
return serializeXml;
}
catch (Exception ex)
{
return string.Empty;
}
}
}
回答by computerGuyCJ
Thanks for the MemoryStream approach, Marc. I thought sure there was a mistake in when I saw "this" in the arguments, but surprisingly the compiler actually lets you do it that way, huh? I made a slight change and chose to override to Equals() instead. Kudos also for using length and array comparison rather than SequenceEquals(). Takes an extra minute to write, but according to http://www.dotnetperls.com/sequenceequal, the performance is much better.
感谢使用 MemoryStream 方法,Marc。当我在参数中看到“this”时,我认为肯定有错误,但令人惊讶的是,编译器实际上允许您这样做,是吗?我做了一个小改动,并选择覆盖 Equals()。使用长度和数组比较而不是 SequenceEquals() 也值得称赞。编写需要额外的一分钟,但根据http://www.dotnetperls.com/sequenceequal,性能要好得多。
public override bool Equals(object obj)
{
// If comparison object is null or is a different type, no further comparisons are necessary...
if (obj == null || GetType() != obj.GetType())
{
return false;
}
// Compare objects using byte arrays...
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
// Get byte array of "this" object...
binaryFormatter.Serialize(memStream, this);
byte[] b1 = memStream.ToArray();
// Get byte array of object to be compared...
memStream.SetLength(0);
binaryFormatter.Serialize(memStream, obj);
byte[] b2 = memStream.ToArray();
// Compare array sizes. If equal, no further comparisons are necessary...
if (b1.Length != b2.Length)
return false;
// If sizes are equal, compare each byte while inequality is not found...
for (int i = 0; i < b1.Length; i++)
{
if (b1[i] != b2[i])
return false;
}
}
return true;
}
回答by Gokul E
My Working solution.!
我的工作解决方案。!
private bool Compare(object obj1, object obj2)
{
if (obj1 == null || obj2 == null)
{
return false;
}
if (!obj1.GetType().Equals(obj2.GetType()))
{
return false;
}
Type type = obj1.GetType();
if (type.IsPrimitive || typeof(string).Equals(type))
{
return obj1.Equals(obj2);
}
if (type.IsArray)
{
Array first = obj1 as Array;
Array second = obj2 as Array;
var en = first.GetEnumerator();
int i = 0;
while (en.MoveNext())
{
if (!Compare(en.Current, second.GetValue(i)))
return false;
i++;
}
}
else
{
foreach (PropertyInfo pi in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
var val = pi.GetValue(obj1);
var tval = pi.GetValue(obj2);
if (!Compare(val, tval))
return false;
}
foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
var val = fi.GetValue(obj1);
var tval = fi.GetValue(obj2);
if (!Compare(val, tval))
return false;
}
}
return true;
}
Hope it helps.!
希望能帮助到你。!