前の出版物では、デバイスの機能と.NETプラットフォームの構造の動作を調べました。これは、オブジェクトの値による比較のコンテキストでの「値による型」( 構造のインスタンス)です。
次に、オブジェクトの値による比較の実装の既製の例、つまり構造体のインスタンスについて考えてみましょう。
構造体の例は、サブジェクト(ドメイン)の観点から、一般に値によってオブジェクトを比較する適用範囲をより正確に決定するのに役立ち、それによってオブジェクトの値によって比較例を単純化します- 前のいずれかで導出された参照型(参照型)であるクラスのインスタンス出版物 ?
PersonStruct構造:
struct PersonStructusing 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;
構造の値でオブジェクトを比較する実装の例は、構造のインスタンスがnull値を受け入れられないという事実と、ユーザー定義の構造 (ユーザー定義の構造)から継承できないという事実により、ボリュームが小さく構造が単純ですオブジェクトの値-継承を考慮したクラスのインスタンスは、このサイクルの4番目の公開で考慮されます)。
前の例と同様に、比較用のフィールドが定義され、GetHashCode()メソッドが実装されています。
メソッドと比較演算子は、次のように順番に実装されます。
静的メソッドPersonStruct.Equals(PersonStruct、PersonStruct)を実装して、構造の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)、およびその結果として、オブジェクトの構造のインスタンスをパッケージ化します。
PersonStruct.Equals(PersonStruct)メソッド(IEquatable(Of PersonStruct)を実装)は、PersonStruct.Equals(PersonStruct、PersonStruct)メソッドを呼び出すことで実装されます。
- 1つまたは2つのNullable(Of PersonStruct)インスタンスが比較に関係している場合、 構造体 のインスタンスのオブジェクトへのパッキングを防ぐために、以下が実装されます。
PersonStruct.Equals(PersonStruct?、PersonStruct?)メソッド-少なくとも1つの引数がNullable(Of PersonStruct)のインスタンスである場合、両方の引数の構造のインスタンスがオブジェクトに パックされ、 Object.Equals(Object、Object)メソッドを呼び出すのを防ぎます。 このメソッドは、演算子をサポートしない言語でNullable(Of PersonStruct)インスタンスを比較するときにも使用できます。 このメソッドは、PersonStruct。==(PersonStruct、PersonStruct)演算子の呼び出しとして実装されます。 メソッドの横には、C#コンパイラが上記のT. ==(T、T)およびT.!=(T、T)演算子を使用する「マジック」をサポートしていない場合にこのメソッドを実装する方法を示すコメント付きコードがあります。 Nullable(Of T)引数。
PersonStruct.Equals(PersonStruct?)メソッド(IEquatable(Of PersonStruct?)インターフェイスの実装)-Nullable(Of PersonStruct)引数がオブジェクトにパックされ、PersonStruct.Equals(Object)メソッドを呼び出すのを防ぎます。 このメソッドは、PersonStruct。==演算子(PersonStruct、PersonStruct)の呼び出しとしても実装されており、コンパイラーの「マジック」がない場合はコメントアウトされた実装コードが使用されます。
- 最後に、Object.Equals(Object)メソッドをオーバーライドするPersonStruct.Equals(Object)メソッドが実装されます。
メソッドは、 is演算子を使用して引数の型と現在のオブジェクトの型の互換性を確認し、引数をPersonStructにキャストし、PersonStruct.Equals(PersonStruct、PersonStruct)を呼び出すことで実装されます。
注:
- IEquatable(Of PersonStruct?)-IEquatable(Of Nullable(Of PersonStruct))インターフェイスの実装は、予想よりも頻繁にラップされる構造で作業するときにプラットフォームの特定の問題を示すために提供されています。
- 実際のプロジェクトでは、パフォーマンスを特に最適化する必要がない場合にのみ、IEquatable(Of Nullable(Of T))を実装するのはアーキテクチャ上の理由によるものではありません-他の型の型Tに型付きIEquatableを実装しないでください
- また、一般に、プラットフォーム自体で最適化が実行されていなくても、さまざまな時期尚早な最適化でコードを乱雑にするべきではありません。 この出版物では、構造を操作するときにパッケージングが実行される頻度についても説明します。
構造体の場合、値でインスタンスを比較する徹底的な実装は、ユーザー定義の構造体の継承がないため、またnullチェックの必要がないため、非常にシンプルでコンパクトになりました。
(ただし、クラスの実装と比較して、 Nullable(Of T)引数をサポートする新しいロジックが登場しました)。
次の出版物では、トピック「オブジェクトの平等」に関するサイクルを要約します。 考慮してください:
- どのような場合でも、主題と技術的な観点から、値によるオブジェクトの値の比較を実装することは本当に望ましいです。
- これらの場合、オブジェクトの値による比較の実装を単純化する方法- 構造体の単純化された実装の経験を考慮して、 参照型(参照型)であるクラスのインスタンス。