.net 对于具有大量字段的对象,是否有更好的方法实现Equals?

.net 对于具有大量字段的对象,是否有更好的方法实现Equals?,.net,unit-testing,design-patterns,dto,.net,Unit Testing,Design Patterns,Dto,另见 我有很多数据传输对象(DTO),每个对象都包含许多简单字段。我需要在所有这些代码上实现Equals(这样我就可以用WCF编写一些单元测试) 我使用的代码是: public override bool Equals(object rhs) { RequestArguments other = rhs as RequestArguments; return other != null && other.m_RequestId.E

另见

我有很多数据传输对象(DTO),每个对象都包含许多简单字段。我需要在所有这些代码上实现Equals(这样我就可以用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);
}
一定有更好的办法(列出所有字段相当于询问错误和维护问题)

我们有目标。MemberwiseClone()可以帮助处理Cloning()案例,但我找不到任何有助于处理Equals的内容。 我们在完全信任的情况下运行,因此基于反射的解决方案是一个答案,但我宁愿不重新发明轮子


(很抱歉,我们没有从特定于域的语言生成DTO,否则这类事情会很容易!而且我无法更改生成系统以添加另一个步骤)

您可以拥有对象哈希的概念-每当对象更改时,您都要支付更新哈希的费用(其中散列实际上是所有连接属性的散列)。然后,如果你有一堆很少更改的对象,比较它们真的很便宜。当然,价格是在对象编辑时支付的。

一个选项是使用反射获取所有可用字段,然后获取并比较所需对象上的值。这将为你提供一个通用的解决方案,但你会有相当多的选择要做的一件事,可能是像Alex建议的那样使用哈希,这是一个更干净的解决方案


编辑:下面是一个使用反射比较对象的简单示例,它查看属性而不是字段,但您得到了这样的想法:

编辑:抱歉,我没有注意到您要求进行序列化测试。因此这种方法显然不适用于您


还有另一种“肮脏”的方式。如果你的对象仍然可以序列化,你可以序列化它们并比较结果流

这相当缓慢,但应该相当可靠且易于实现


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

有趣的是,你应该问,我最近发布了一些代码来做这件事。请查看我的,看看它是否符合你的需要

它使用起来非常简单,效率也非常高。它使用IL emit在第一次运行时生成整个Equals和GetHashCode函数(对于使用的每个类型一次)。它将使用该类型的默认相等比较器(EqualityComparer.default)比较给定对象的每个字段(私有或公共).我们已经在生产中使用了一段时间,它看起来很稳定,但我不保证=)

它处理了在使用自己的equals方法时很少想到的所有pescy边缘情况(即,除非您先将对象装箱到一个对象中,并解决了更多与null相关的问题,否则无法将自己的对象与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);
}
public override int GetHashCode()
{
返回MemberwiseEqualityComparer.Default.GetHashCode(this);
}
公共覆盖布尔等于(对象对象对象)
{
if(obj==null)
返回false;
收益等于(obj为Foo);
}
公共覆盖布尔等于(Foo其他)
{
返回MemberwiseEqualityComparer.Default.Equals(此,其他);
}

MemberwiseEqualityComparer是在Meaning下发布的,您可以使用它做任何您想做的事情,包括在专有解决方案中使用它,而无需更改您的许可证。

这并不能解决任何问题,您仍然需要手动散列所有字段。这不允许我测试对象是否使用WCF正常传输,它只是添加了更多的代码来做错事!此外,您需要使用一个完美的散列来避免冲突。具体要做什么工作?只需使用代码属性标记DTO字段,并在反射过程中使用该属性来选择要比较的字段。该死的,你甚至可以使用DTOEquals方法,这样如果你有对象的话,你根本就不必使用equals。我希望有人能给我指一个类似这样的预封装实现。是的,但是我希望测试序列化,所以在我的例子中这不是一个好的解决方案。我编写了一个序列化测试程序,它从头开始创建对象,序列化它们,并使用大量反射对它们进行比较。它是高度可配置的,由两千行或更多行代码组成。我想在LGPL下发布它,但必须先问我的老板并清理一下。所以现在它对您没有帮助。是的,而且不要忘记您需要检查对象中的每个引用字段是否为null,或者您可以在Equals中获得NRE:(Dup线程,答案在这里:谢谢,这看起来很棒;但是对于我来说,要允许使用它,它必须在一个标准的开源代码站点上,有很好的文档记录,并且有很好的单元测试覆盖率。如果这个问题还没有一个公认的开源解决方案,你有机会成为那个解决方案。嗨,伊恩。如果你检查在页面底部,您将看到我已根据MIT许可证对其进行了许可。这是最宽松的开放源码许可证之一,因此使用它应该不会有任何问题=)我会更新我的答案来做记录。你好,伊恩。看来我的回答有点仓促,在我阅读完你的全部评论之前就回答了。对此我很抱歉。我肯定可以发布我们为EqualityComparer编写的单元测试,但我必须先与我的公司联系,这样我才能得到你的许可o根据麻省理工学院的许可证进行许可。我马上就要开始了。检查我的网站是否有更新。至于标准开源代码网站,我认为这段代码对于像Google code这样的大型代码托管网站来说有点太小了,不是吗?@Markus我刚刚看到这个问题是重复的。您可能希望添加您的答案