71

Equals言語の設計者が、値型と同様に匿名型にEqualsを実装することにした理由を疑問に思っています。誤解を招きませんか?

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public static void ProofThatAnonymousTypesEqualsComparesBackingFields()
{
    var personOne = new { Name = "Paweł", Age = 18 };
    var personTwo = new { Name = "Paweł", Age = 18 };

    Console.WriteLine(personOne == personTwo); // false
    Console.WriteLine(personOne.Equals(personTwo)); // true
    Console.WriteLine(Object.ReferenceEquals(personOne, personTwo)); // false

    var personaOne = new Person { Name = "Paweł", Age = 11 };
    var personaTwo = new Person { Name = "Paweł", Age = 11 };
    Console.WriteLine(personaOne == personaTwo); // false
    Console.WriteLine(personaOne.Equals(personaTwo)); // false
    Console.WriteLine(Object.ReferenceEquals(personaOne, personaTwo)); // false
}

一見すると、出力されるブール値はすべてfalseである必要があります。ただし、 typeが使用され、anonymous typeが使用されると、Equals呼び出しのある行は異なる値を返します。Person

4

4 に答える 4

77

匿名型インスタンスは、動作やIDのない不変のデータ値です。参照することはあまり意味がありません-それらを比較してください。その文脈では、それらの構造的同等性の比較を生成することは完全に合理的だと思います。

比較動作をカスタム(参照比較または大文字と小文字を区別しない)に切り替える場合は、Resharperを使用して匿名型を名前付きクラスに変換できます。Resharperは平等メンバーを生成することもできます。

これを行う非常に実用的な理由もあります。匿名型は、LINQ結合およびグループ化でハッシュキーとして使用すると便利です。そのため、意味的に正しい実装が必要EqualsですGetHashCode

于 2012-08-25T16:05:31.767 に答える
39

理由の部分については、言語設計者に尋ねる必要があります...

しかし、これは、匿名タイプがアセンブリ内で統合されることに関するEric Lippertの記事、パート2で見つかりました。

匿名型は、名前と値のペアの小さな不変のセットを格納するのに便利な場所を提供しますが、それ以上のものを提供します。また、Equals、GetHashCode、およびこの議論に最も密接に関係するToStringの実装も提供します。(*)

理由の部分がメモのどこにあるか:

(*)EqualsとGetHashCodeを提供するため、LINQクエリで匿名型のインスタンスを結合を実行するためのキーとして使用できます。LINQ to Objectsは、パフォーマンス上の理由からハッシュテーブルを使用して結合を実装するため、EqualsとGetHashCodeを正しく実装する必要があります。

于 2012-08-25T16:12:12.193 に答える
22

C#言語仕様からの公式回答(ここで入手可能):

匿名型のEqualsメソッドとGetHashcodeメソッドは、オブジェクトから継承されたメソッドをオーバーライドし、プロパティのEqualsメソッドとGetHashcodeで定義されるため、同じ匿名型の2つのインスタンスは、すべてのプロパティが等しい場合にのみ等しくなります。

(私の強調)

他の回答は、これが行われる理由を説明しています。

VB.Netでは実装が異なることに注意してください。

キープロパティを持たない匿名型のインスタンスは、それ自体とのみ同等です。

匿名型オブジェクトを作成するときは、キープロパティを明示的に指定する必要があります。デフォルトは次のとおりです。キーなし。これはC#ユーザーにとって非常に混乱する可能性があります。

これらのオブジェクトはVBでは等しくありませんが、C#と同等のコードになります。

Dim prod1 = New With {.Name = "paperclips", .Price = 1.29}
Dim prod2 = New With {.Name = "paperclips", .Price = 1.29}

これらのオブジェクトは「等しい」と評価されます。

Dim prod3 = New With {Key .Name = "paperclips", .Price = 1.29}
Dim prod4 = New With {Key .Name = "paperclips", .Price = 2.00}
于 2012-08-25T18:13:45.470 に答える
9

それは私たちに役立つ何かを与えるからです。次のことを考慮してください。

var countSameName = from p in PersonInfoStore
  group p.Id by new {p.FirstName, p.SecondName} into grp
  select new{grp.Key.FirstName, grp.Key.SecondName, grp.Count()};

匿名型の実装はフィールドごとの同等性に基づいて機能するEquals()ため、機能します。GetHashCode()

  1. これは、PersonInfoStore linq-to-objectsではないatに対して実行すると、上記が同じクエリに近くなることを意味します。(それでも同じではありませんが、XMLソースの動作とは一致しますが、ほとんどのデータベースの照合結果とは一致しません)。
  2. IEqualityComparerつまり、匿名オブジェクトを使用してグループ化を非常に困難にするすべての呼び出しを定義する必要はありませんGroupBy。匿名オブジェクトのIEqualityComparerを定義することは可能ですが、簡単ではありません。最も自然な意味からはほど遠いものです。
  3. とりわけ、ほとんどの場合、問題は発生しません。

3番目のポイントは検討する価値があります。

値型を定義するとき、当然、値ベースの平等の概念が必要です。特定のフィールドをケースに依存せずに一致させるなど、その値ベースの同等性についてはデフォルトとは異なる考えがあるかもしれませんが、デフォルトは当然のことです(パフォーマンスが低く、1つのケースでバグがある場合*)。(また、この場合、参照の同等性は無意味です)。

参照型を定義するとき、値ベースの平等の概念が必要な場合と不要な場合があります。デフォルトでは参照の同等性が得られますが、これは簡単に変更できます。私たちがそれを変更する場合、私たちはそれをちょうどEqualsそしてGetHashCodeまたは彼らのためにそしてまたそれを変更することができます==

匿名型を定義するとき、まあ、それを定義しませんでした。それが匿名の意味です!参照の同等性を気にするシナリオのほとんどは、もうありません。後で別のオブジェクトと同じかどうか疑問に思うほど長い間オブジェクトを保持する場合は、匿名オブジェクトを処理していない可能性があります。私たちが価値に基づく平等を気にするケースはたくさんあります。非常に頻繁にLinqを使用し(上記でGroupBy見たように、、、、、、、、および) Distinct、他Unionの用途を使用することもよくあります(Linqが2.0で列挙可能なものを使用して実行していたことを、それ以前にある程度実行していなかったわけではありません。 2.0でコーディングする人は、メソッドの半分を自分で記述しているはずです)。GroupJoinIntersectSequenceEqualToDictionaryToLookupEnumerable

全体として、匿名クラスで平等が機能する方法から多くのことを得ることができます。

誰かが本当に参照の平等を望んでいるという偶然では、参照の平等を==使用することは、彼らがまだそれを持っていることを意味するので、私たちは何も失うことはありません。それが進むべき道です。

*とのデフォルトの実装にはEquals()GetHashCode()安全な場合にバイナリ一致を使用できるようにする最適化があります。残念ながら、バグがあり、安全でない場合でも、このより高速なアプローチに対して安全であると誤認されることがあります(または、少なくとも以前は修正されていた可能性があります)。一般的なケースはdecimal、構造体にフィールドがある場合、同等のフィールドを持ついくつかのインスタンスが等しくないと見なされることです。

于 2012-08-25T18:55:14.047 に答える