另见Hows to quick check if data transfer two objects have equal properties in C#?
我有很多数据传输对象(DTO),每个数据传输对象都包含许多简单字段。我需要在所有这些上实现Equals(所以我可以编写一些单元测试来运行它们var WCF)。
我使用的代码是:
public override bool Equals(object rhs)
{
RequestArguments other = rhs as RequestArguments;
return
other != null &&
other.m_RequestId.Equals(RequestId) &&
other.m_Type.Equals(m_Type) &&
other.m_Parameters.Equals(m_Parameters) &&
other.m_user.Equals(m_user);
}
必须有更好的方法!... (列出所有字段,而不是要求错误和维护问题)
E.g。我们有对象。 MemberwiseClone()帮助克隆()案例,但我找不到任何帮助Equals的东西。 我们完全信任,所以基于反射的解决方案是一个答案,但我宁愿不重新发明轮子。
(抱歉,我们不会使用特定于域的语言生成DTO,否则这种事情会很简单!我也无法更改构建系统以添加其他步骤)
答案 0 :(得分:3)
有趣的是你应该问,我最近发布了一些代码来完成这个。查看我的MemberwiseEqualityComparer,了解它是否符合您的需求。
它非常易于使用且效率也很高。它使用IL-emit在第一次运行时生成整个Equals和GetHashCode函数(对于每种类型使用一次)。它将使用该类型的默认相等比较器(EqualityComparer.Default)比较给定对象的每个字段(私有或公共)。我们已经在生产中使用了一段时间,看起来很稳定,但我不会保证=)
它会处理你在滚动自己的equals方法时很少想到的所有那些pescy edge-cases(也就是说,你不能将你自己的对象与null进行比较,除非你先将它装入一个对象中和很多关于无关的问题)。
我一直想写一篇关于它的博客文章,但还没有找到它。代码有点没有文档但如果你喜欢它我可以清理一下。
public override int GetHashCode()
{
return MemberwiseEqualityComparer<Foo>.Default.GetHashCode(this);
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
return Equals(obj as Foo);
}
public override bool Equals(Foo other)
{
return MemberwiseEqualityComparer<Foo>.Default.Equals(this, other);
}
MemberwiseEqualityComparer是在MIT license下发布的,你可以随心所欲地使用它,包括在专有解决方案中使用它,而不会改变你的许可。
答案 1 :(得分:1)
一个选项是使用反射来获取所有可用字段,然后获取并比较它们在所需对象上的值。这将为您提供一个通用的解决方案,但您可能需要做很多工作,可能使用哈希,因为Alex建议这是一个更清洁的解决方案。
编辑:这是一个使用反射比较对象的简单示例,它会查看属性而不是字段,但您会明白:http://www.willasrari.com/blog/use-systemreflection-for-comparing-custom-objects/000257.aspx
答案 2 :(得分:0)
您可以拥有对象哈希的概念 - 只要对象发生更改,您就需要为更新哈希付出代价(哈希就是所有连接属性的哈希值)。然后,如果你有一堆很少改变的对象,比较它们真的很便宜。当然,价格是在对象编辑时支付的。
答案 3 :(得分:0)
编辑:抱歉,我没有注意到您要求进行序列化测试。所以这种方法绝对不适合你。
还有另一种“肮脏”的方式。如果您的对象无论如何都是可序列化的,您可以序列化它们并比较生成的流。
这很慢,但应该非常可靠且易于实施。
我们有时会这样做,以检查是否有人在编辑器中更改了任何数据。