多くのフィールドを持つオブジェクトに対して Equals を実装するより良い方法はありますか?
-
11-09-2019 - |
質問
こちらも参照 データ転送2つのオブジェクトがC#で等しい特性を持っているかどうかを迅速に確認するにはどうすればよいですか?
それぞれに含まれるデータ転送オブジェクト (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);
}
もっと良い方法があるはずです...! (すべてのフィールドをリストすると、むしろエラーやメンテナンスの問題が発生します)
例えば。オブジェクトがあります。Cloning() の場合には MemberwiseClone() が役立ちますが、Equals に関しては役立つものが見つかりません。私たちは完全な信頼のもとで実行しているので、リフレクション ベースのソリューションが 1 つの答えですが、私は車輪の再発明はしません。
(申し訳ありませんが、ドメイン固有の言語から DTO を生成しません。そうでなければ、この種のことは簡単です。また、ビルドシステムを変更して別のステップを追加することもできません)
解決
おかしなことに、私は最近まさにそれを行うためのコードを公開しました。私のものをチェックしてください MemberwiseEqualityComparer それがあなたのニーズに合うかどうかを確認してください。
とても使いやすく、非常に効率的です。IL-emit を使用して、最初の実行時に Equals 関数と GetHashCode 関数全体を生成します (使用する型ごとに 1 回)。これは、その型のデフォルトの等価比較子 (EqualityComparer.Default) を使用して、指定されたオブジェクトの各フィールド (プライベートまたはパブリック) を比較します。しばらく実稼働環境で使用しており、安定しているようですが、保証はしません =)
これは、独自のequalsメソッドをロールするときにめったに考えられない厄介なエッジケースをすべて処理します(つまり、最初にオブジェクトをボックス化してロットをオフにしない限り、独自のオブジェクトを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ライセンス つまり、ライセンスを少し変更することなく、独自のソリューションでの使用を含め、これを使用してほとんど何でもできるということです。
他のヒント
オプションとしては、リフレクションを使用して利用可能なフィールドをすべて取得し、目的のオブジェクトでそれらの値を取得して比較することです。これで一般的な解決策が得られますが、かなりの作業が必要になるでしょう。おそらく、アレックスが提案するようにハッシュを使用する方がよりクリーンな解決策です。
編集:これは、リフレクションを使用してオブジェクトを比較する簡単な例です。フィールドではなくプロパティを参照しますが、アイデアはわかります。 http://www.willasrari.com/blog/use-systemreflection-for-comparing-custom-objects/000257.aspx
オブジェクト ハッシュの概念を持つことができます。オブジェクトが変更されるたびに、ハッシュを更新する代償を支払います (ハッシュは文字通り、すべての連結されたプロパティのハッシュです)。そうすれば、めったに変更されないオブジェクトが多数ある場合、それらを比較するのは非常に安価になります。もちろん、料金はオブジェクトの編集時に支払われます。
編集:申し訳ありませんが、シリアル化テストを求めていることに気づきませんでした。したがって、このアプローチはあなたにとっては間違いなく機能しません。
もう一つ「汚い」方法があります。とにかくオブジェクトがシリアル化可能であれば、次のことができます シリアライズ それらを比較し、結果のストリームを比較します。
これはかなり遅いですが、非常に信頼性が高く、実装も簡単です。
誰かがエディター内のデータを変更したかどうかを確認するために、これを時々実行します。