是否有更好的方法为具有大量字段的对象实现Equals?

时间:2009-12-02 09:33:09

标签: .net unit-testing design-patterns dto

  

另见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,否则这种事情会很简单!我也无法更改构建系统以添加其他步骤)

4 个答案:

答案 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)

编辑:抱歉,我没有注意到您要求进行序列化测试。所以这种方法绝对不适合你。


还有另一种“肮脏”的方式。如果您的对象无论如何都是可序列化的,您可以序列化它们并比较生成的流。

这很慢,但应该非常可靠且易于实施。

我们有时会这样做,以检查是否有人在编辑器中更改了任何数据。