値によるオブジェクトの比較について-6:構造平等の実装

前の出版物では、デバイスの機能と.NETプラットフォームの構造の動作を調べました。これは、オブジェクトの値による比較のコンテキストでの「値による型」( 構造のインスタンス)です。







次に、オブジェクトの値による比較の実装の既製の例、つまり構造体のインスタンスについて考えてみましょう。







構造体の例は、サブジェクト(ドメイン)の観点から、一般に値によってオブジェクトを比較する適用範囲をより正確に決定するのに役立ち、それによってオブジェクトの値によって比較例を単純化します- 前のいずれかで導出された参照型(参照型)であるクラスのインスタンス出版物







PersonStruct構造:







struct PersonStruct
using System; namespace HelloEquatable { public struct PersonStruct : IEquatable<PersonStruct>, IEquatable<PersonStruct?> { private static int GetHashCodeHelper(int[] subCodes) { int result = subCodes[0]; for (int i = 1; i < subCodes.Length; i++) result = unchecked(result * 397) ^ subCodes[i]; return result; } private static string NormalizeName(string name) => name?.Trim() ?? string.Empty; private static DateTime? NormalizeDate(DateTime? date) => date?.Date; public string FirstName { get; } public string LastName { get; } public DateTime? BirthDate { get; } public PersonStruct(string firstName, string lastName, DateTime? birthDate) { this.FirstName = NormalizeName(firstName); this.LastName = NormalizeName(lastName); this.BirthDate = NormalizeDate(birthDate); } public override int GetHashCode() => GetHashCodeHelper( new int[] { this.FirstName.GetHashCode(), this.LastName.GetHashCode(), this.BirthDate.GetHashCode() } ); public static bool Equals(PersonStruct first, PersonStruct second) => first.BirthDate == second.BirthDate && first.FirstName == second.FirstName && first.LastName == second.LastName; public static bool operator ==(PersonStruct first, PersonStruct second) => Equals(first, second); public static bool operator !=(PersonStruct first, PersonStruct second) => !Equals(first, second); public bool Equals(PersonStruct other) => Equals(this, other); public static bool Equals(PersonStruct? first, PersonStruct? second) => first == second; // Alternate version: //public static bool Equals(PersonStruct? first, PersonStruct? second) => // first.HasValue == second.HasValue && // ( // !first.HasValue || Equals(first.Value, second.Value) // ); public bool Equals(PersonStruct? other) => this == other; // Alternate version: //public bool Equals(PersonStruct? other) => // other.HasValue && Equals(this, other.Value); public override bool Equals(object obj) => (obj is PersonStruct) && Equals(this, (PersonStruct)obj); // Alternate version: //public override bool Equals(object obj) => // obj != null && // this.GetType() == obj.GetType() && // Equals(this, (PersonStruct)obj); } }
      
      





構造の値でオブジェクトを比較する実装の例は、構造のインスタンスがnull値を受け入れられないという事実と、ユーザー定義の構造 (ユーザー定義の構造)から継承できないという事実により、ボリューム小さく構造が単純ですオブジェクトの値-継承を考慮したクラスのインスタンスはこのサイクルの4番目の公開で考慮されます)。







前の例と同様に、比較用のフィールドが定義され、GetHashCode()メソッドが実装されています。







メソッドと比較演算子は、次のように順番に実装されます。







  1. 静的メソッドPersonStruct.Equals(PersonStruct、PersonStruct)を実装して、構造の2つのインスタンスを比較しました。

    このメソッドは、他のメソッドと演算子を実装するときの参照比較メソッドとして使用されます。

    また、このメソッドを使用して、演算子をサポートしない言語の構造のインスタンスを比較できます。







  2. 演算子PersonStruct。==(PersonStruct、PersonStruct)およびPersonStruct。!=(PersonStruct、PersonStruct)が実装されています。

    C#コンパイラには興味深い機能があることに注意してください。







    • 構造Tに演算子T. ==(T、T)とT.!=(T、T)がオーバーロードされている場合、 Nullable(Of T)構造の場合、演算子T. ==(T、T)を使用して比較の可能性も表示されますおよびT.!=(T、T)。
    • これはおそらく、コンパイラの「魔法」であり、値の等価性を直接チェックする前に構造のインスタンスの値の存在をチェックし、構造インスタンスをオブジェクトに パッキングすることはありません。
    • 通常、この場合、 Nullable(Of T)構造体のインスタンスを型指定されていないnullと比較すると、演算子T. ==(T、T)またはT.!=(T、T)が呼び出されますが、構造体のインスタンスも同様に比較されます過負荷演算子T. ==(T、T)およびT.!=(T、T)を持たないNullable(Of T)は、演算子Object。==(Object、Object)またはObject。!=(Object 、Object)、およびその結果として、オブジェクトの構造のインスタンスをパッケージ化します。


  3. PersonStruct.Equals(PersonStruct)メソッド(IEquatable(Of PersonStruct)を実装)は、PersonStruct.Equals(PersonStruct、PersonStruct)メソッドを呼び出すことで実装されます。







  4. 1つまたは2つのNullable(Of PersonStruct)インスタンスが比較に関係している場合、 構造体 インスタンスのオブジェクトへのパッキングを防ぐために、以下が実装されます。




注:









構造体の場合、値でインスタンスを比較する徹底的な実装は、ユーザー定義の構造体の継承がないため、またnullチェックの必要がないため、非常にシンプルでコンパクトになりました。

(ただし、クラスの実装と比較して、 Nullable(Of T)引数をサポートする新しいロジックが登場しました)。







次の出版物では、トピック「オブジェクトの平等」に関するサイクルを要約します。 考慮してください:










All Articles