Kami telah menganalisis kekhasan struct kerangka .NET yang mewakili Tipe Nilai saat membandingkan objek berdasarkan nilai – contoh struct.
Sekarang, saya akan menjelaskan proses ini pada contoh tertentu untuk memeriksa apakah itu akan memungkinkan kita untuk menentukan penggunaan perbandingan objek berdasarkan nilai secara umum dan dengan demikian, untuk menyederhanakan sampel membandingkan objek berdasarkan nilai – contoh kelas yang mewakili referensi jenis.
Struktur 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); } }
Seperti yang Anda lihat, contoh ini lebih kecil dan lebih mudah berdasarkan struktur, karena instance struct tidak nol dan tidak mungkin mewarisi dari struct yang ditentukan pengguna. Kami telah membahas kekhasan untuk menerapkan perbandingan berdasarkan nilai untuk instance kelas di artikel saya sebelumnya.
Selain itu, kami telah menentukan bidang untuk perbandingan objek serta mengimplementasikan metode GetHashCode().
Metode dan operator perbandingan telah diimplementasikan dalam urutan berikut:
- Untuk membandingkan dua contoh struct, kami telah mengimplementasikan metode statis PersonStruct.Equals(PersonStruct, PersonStruct). Kami akan menggunakan metode ini sebagai metode perbandingan referensi ketika menerapkan metode dan operator lain. Selain itu, ini dapat diterapkan untuk membandingkan contoh struct dalam bahasa yang tidak mendukung operator.
- Operator PersonStruct.==(PersonStruct, PersonStruct) dan PersonStruct.!=(PersonStruct, PersonStruct) juga telah diimplementasikan. Perlu dicatat bahwa kompiler C# memiliki kekhasan berikut:
- Anda dapat membandingkan dengan operator yang kelebihan beban T.==(T, T) dan T.!=(T, T) di Nullable(Of T)
- Sebelum memeriksa kesetaraan nilai, kompiler dapat memverifikasi apakah instance struct memiliki nilai yang valid. Selain itu, kompiler tidak membungkus instance struct menjadi objek.
- Jadi, membandingkan instance dari struktur Nullable(Of T) dengan nilai nullable yang tidak diketik mengarah ke pemanggilan operator ==(T, T) atau T.!=(T, T), sambil membandingkan instance dari Nullable( Dari T) struktur tanpa operator yang kelebihan beban T.==(T, T)dan T.!=(T, T) menghasilkan pemanggilan operator Object.==(Object, Object) atau Object.!=(Object, Object) dan, sebagai hasilnya, dalam membungkus sebuah instance ke dalam objek.
- Metode PersonStruct.Equals(PersonStruct) (implementasi IEquatable(Of PersonStruct)) telah diimplementasikan dengan memanggil metode PersonStruct.Equals(PersonStruct, PersonStruct).
- Untuk menghindari membungkus instance struct menjadi objek, ketika kita memiliki satu atau dua instance Nullable(Of PersonStruct), dimungkinkan untuk menerapkan metode berikut:
- PersonStruct.Equals(PersonStruct?, PersonStruct?), sebagai panggilan dari operator PersonStruct.==(PersonStruct, PersonStruct), digunakan untuk menghindari membungkus instance struct dari kedua argumen ke dalam objek dan memanggil Object.Equals( Object, Object) metode jika setidaknya salah satu argumen adalah contoh Nullable(Of PersonStruct). Selain itu, Anda dapat menggunakan metode ini untuk membandingkan instance Nullable(Of PersonStruct) dalam bahasa yang tidak mendukung operator. Dalam kode, Anda mungkin menemukan komentar yang menjelaskan bagaimana metode ini dapat diimplementasikan jika kompiler C# tidak dapat menggunakan operator T.==(T, T) dan T.!=(T, T) untuk Nullable(Of T) argumen.
- PersonStruct.Equals(PersonStruct?) – implementasi antarmuka IEquatable(Of PersonStruct?) yang digunakan untuk menghindari penggabungan argumen Nullable(Of PersonStruct) ke dalam objek dan memanggil metode PersonStruct.Equals(Object). Ini diimplementasikan sebagai panggilan operator PersonStruct.==(PersonStruct, PersonStruct) dengan kode yang dikomentari untuk menggunakan operator T.==(T, T) dan T.!=(T, T) untuk Nullable(Of T ) argumen.
- PersonStruct.Equals(Object) – yang menggantikan metode Object.Equals(Object). Ini diimplementasikan dengan memeriksa kompatibilitas tipe argumen dengan tipe objek saat ini menggunakan operator is dengan melemparkan argumen ke PersonStruct dan memanggil PersonStruct.Equals(PersonStruct, PersonStruct).
Catatan:
- Implementasi antarmuka IEquatable(Of PersonStruct?) — IEquatable(Of Nullable(Of PersonStruct))berfungsi untuk menunjukkan masalah tertentu di platform saat bekerja dengan struct di mana membungkus instance menjadi objek terjadi lebih cepat dari yang kita harapkan.
- Dalam proyek nyata, asalkan tidak perlu untuk meningkatkan kinerja, implementasi IEquatable(Of Nullable(Of T)) tidak berlaku karena alasan arsitektur – kita tidak boleh mengimplementasikan IEquatable yang diketik dalam tipe T untuk tipe apa pun.
- Secara umum, tidak perlu membanjiri kode dengan pengoptimalan yang berbeda.
Untuk struktur, kami dapat membuat perbandingan berdasarkan nilai menjadi lebih sederhana dan lebih produktif dengan menghindari pewarisan struct yang ditentukan Pengguna dan perlu memeriksa objek pada null. Selain itu, kita dapat memantau logika baru yang mendukung argumen Nullable(Of T).
Dalam publikasi saya di masa mendatang, saya akan merangkum poin-poin berikut:
- Kapan sebaiknya menerapkan perbandingan objek berdasarkan nilai;
- Bagaimana kami dapat menyederhanakan implementasi perbandingan berdasarkan nilai untuk objek – instance kelas yang mewakili tipe referensi.
Baca juga:
Membandingkan Objek dengan Nilai. Bagian 1:Awal
Membandingkan Objek dengan Nilai. Bagian 2:Catatan Implementasi Metode Setara
Membandingkan Objek dengan Nilai. Bagian 3:Operator Kesetaraan dan Kesetaraan Khusus Jenis
Membandingkan Objek dengan Nilai. Bagian 4:Operator Warisan &Perbandingan
Membandingkan Objek dengan Nilai. Bagian 5:Masalah Kesetaraan Struktur