2

see also Hows to quick check if data transfer two objects have equal properties in C#?

I have lot of Data Transfer Objects (DTO) that each contains lots of simple fields. I need to implement Equals on all of them (so I can write some unit tests off transporting them var WCF).

The code I am using is:

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);
}

There must be a better way!... (listing all the fields is rather asking for errors and maintenance problems)

E.g. we have Object. MemberwiseClone() to help with the Cloning() case, but I cannot find anything to help with Equals. We are running in full trust so a reflection based solution is one answer, but I rather not reinvent the wheel.

(Sorry we don’t generate the DTO from a domain-specific language otherwise this sort of thing would be easy! Also I am not able to change the build system to add another step)

4

4 に答える 4

3

おかしなことに、私は最近、まさにそれを行うためのコードをいくつか公開しました。私のMemberwiseEqualityComparerをチェックして、ニーズに合っているかどうかを確認してください。

それは本当に使いやすく、非常に効率的です。IL-emit を使用して、最初の実行時に Equals および GetHashCode 関数全体を生成します (使用される型ごとに 1 回)。指定されたオブジェクトの各フィールド (プライベートまたはパブリック) を、その型 (EqualityComparer.Default) の既定の等値比較子を使用して比較します。しばらく本番環境で使用しており、安定しているように見えますが、保証はしません =)

独自の equals メソッドをロールしているときにめったに考えない厄介なエッジケースをすべて処理します (つまり、最初にオブジェクトにボックス化し、多くをオフにしない限り、独自のオブジェクトを 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);
}

MemberwiseEqualityComparer はMIT ライセンスの下でリリースされており、ライセンスを少し変更せずにプロプライエタリ ソリューションで使用するなど、ほぼ何でも好きなことができます。

于 2009-12-02T09:50:01.050 に答える
1

オプションは、リフレクションを使用して使用可能なすべてのフィールドを取得し、目的のオブジェクトでそれらの値を取得して比較することです。これにより、一般的な解決策が得られますが、かなりの作業が必要になります。おそらく、アレックスが示唆するようにハッシュを使用する方がクリーンな解決策です。

編集: リフレクションを使用してオブジェクトを比較する簡単な例を次に示します。フィールドではなくプロパティを調べますが、アイデアはわかります: http://www.willasrari.com/blog/use-systemreflection-for-comparing-custom-objects/ 000257.aspx

于 2009-12-02T09:40:01.353 に答える
0

You can have a concept of an object hash - whenever an object changes, you pay the price of updating the hash (where the hash is literally a hash of all concatenated properties). Then, if you have a bunch of objects that rarely change, it's really cheap to compare them. The price, of course, is then paid at object editing time.

于 2009-12-02T09:35:46.573 に答える
0

編集:申し訳ありませんが、シリアル化テストを求めていることに気づきませんでした。したがって、このアプローチは間違いなく機能しません。


別の「汚い」方法があります。とにかくオブジェクトがシリアライズ可能な場合は、それらをシリアライズして、結果のストリームを比較できます。

これはかなり遅いですが、非常に信頼性が高く、実装が簡単です。

誰かがエディターでデータを変更したかどうかを確認するために、時々これを行っています。

于 2009-12-02T09:44:06.620 に答える