Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Tip
Artikel ini adalah bagian dari bagian Dasar-Dasar untuk pengembang yang sudah mengetahui setidaknya satu bahasa pemrograman dan mempelajari C#. Jika Anda baru menggunakan pemrograman, mulailah dengan tutorial Memulai terlebih dahulu.
Berasal dari bahasa lain? Dalam Java, == pada objek dan dalam JavaScript, === pada objek menguji identitas, bukan konten. Kelas C# bekerja dengan cara yang sama secara default. Dalam Python, == memanggil __eq__ dan secara bawaan menguji konten, mirip dengan cara C# records dibandingkan.
Struktur C# juga membandingkan berdasarkan nilai saat Anda memanggil Equals.
C# membedakan dua jenis kesetaraan. Kesetaraan nilai berarti dua instans sama ketika datanya cocok. Kesetaraan referensi berarti dua variabel sama hanya ketika menunjuk ke objek yang sama dalam memori. Kondisi ini juga disebut identitas. Jenis nilai biasanya membandingkan data, dan jenis referensi biasanya membandingkan identitas. Pengembang tipe dapat mengubah nilai bawaan tersebut, tetapi model mental itu mencegah bug yang sulit dideteksi ketika dua objek yang tampak identik tidak dianggap setara, atau ketika mutasi melalui satu variabel diam-diam mengubah nilai yang terlihat oleh variabel lain.
Jenis nilai, jenis referensi, dan default kesetaraan
Setiap jenis dalam C# adalah jenis nilai atau jenis referensi. Jenis nilai menyimpan datanya langsung dalam variabel . Jenis referensi menyimpan referensi ke objek. Saat Anda menetapkan variabel jenis referensi ke variabel lain, kedua variabel merujuk ke objek yang sama. Untuk informasi selengkapnya tentang jenis nilai dan jenis referensi, lihat Ringkasan sistem jenis.
Perilaku kesetaraan default biasanya mengikuti jenis:
-
Tipe numerik bawaan dan enum adalah tipe nilai. Dua
intvariabel sama ketika nilai numeriknya cocok. -
Struktur adalah jenis nilai.
structbiasa menggunakan kesamaan nilai saat Anda memanggil Equals. - Tuple adalah jenis nilai. Dua tuple dianggap sama jika semua nilai elemennya sama.
-
Kelas adalah jenis referensi. Kelas biasa menggunakan kesetaraan referensi, jadi
==dan Equals uji apakah dua variabel menunjuk ke objek yang sama.
Sebuah kelas menggunakan kesamaan referensi. Dua objek terpisah dengan data yang sama tidak sama, tetapi dua variabel yang merujuk ke objek yang sama sama:
var order1 = new Order(42, "Shoes");
var order2 = new Order(42, "Shoes");
Console.WriteLine(order1 == order2); // => False
Console.WriteLine(order1.Equals(order2)); // => False
Console.WriteLine(ReferenceEquals(order1, order2)); // => False
Order order3 = order1;
Console.WriteLine(order1 == order3); // => True
Sebuah struct menunjukkan kesetaraan nilai melalui Equals. Dua instance struct bernilai sama ketika field-fieldnya sama:
var pt1 = new Point(3, 4);
var pt2 = new Point(3, 4);
Console.WriteLine(pt1.Equals(pt2)); // => True
Struct biasa tidak memiliki operator == bawaan. Menulis p1 == p2 di struktur biasa hanya mengkompilasi jika struktur mendeklarasikan sendiri operator ==. Jika Anda memerlukan perbandingan operator untuk struct, tentukan == dan != sebagai pasangan dan tetap konsisten dengan Equals dan GetHashCode.
Tuple juga merupakan tipe nilai. Dua tuple dianggap sama jika nilai setiap elemennya sama. Nama elemen dalam tuple bernama hanyalah kemudahan pada saat kompilasi dan tidak diperhitungkan saat perbandingan. Hanya posisi dan nilai yang penting:
var t1 = (Name: "Grace", Role: "Engineer");
var t2 = (Name: "Grace", Role: "Engineer");
Console.WriteLine(t1 == t2); // => True
Untuk informasi selengkapnya tentang sintaks tuple dan dekonstruksi, lihat Tuple dan dekonstruksi.
Gunakan Object.ReferenceEquals untuk menguji identitas secara langsung
ReferenceEquals selalu menguji identitas terlepas dari bagaimana jenis mengambil alih Equals atau kelebihan beban ==. Gunakan sebagai diagnostik identitas saat Anda perlu mengonfirmasi apakah dua variabel menunjuk ke objek yang sama persis:
var doc1 = new Document("Report");
var doc2 = new Document("Report");
var doc3 = doc1;
Console.WriteLine(ReferenceEquals(doc1, doc2)); // => False
Console.WriteLine(ReferenceEquals(doc1, doc3)); // => True
Salah satu penggunaan umum adalah dalam override Equals untuk melewati perbandingan penuh: ketika kedua argumen merujuk ke referensi yang sama, keduanya selalu dianggap sama tanpa memeriksa setiap field.
Note
Ketika variabel ditik sebagai antarmuka, == memeriksa apakah variabel antarmuka merujuk ke objek yang sama. Pemanggilan Equals tetap menjalankan implementasi objek yang mendasarinya.
Note
ReferenceEquals selalu mengembalikan false saat membandingkan jenis nilai, meskipun kedua argumen berisi nilai yang sama. Perilaku ini terjadi karena setiap argumen jenis nilai dikotak secara independen ke dalam objek tumpukan terpisah saat diteruskan ke ReferenceEquals.
Jenis dapat menentukan semantik kesetaraan yang berbeda
Jenis dapat menentukan semantik kesetaraan yang berbeda dari perilaku default. Alasan paling umum adalah untuk menerapkan kesetaraan nilai. Jika Anda membuat tipe yang merepresentasikan data, seperti rekening bank, produk dalam inventaris, atau pengguna dalam suatu sistem, anggap instans dengan nilai yang sama sebagai setara. Pilih jenis rekaman untuk menerapkan kesetaraan nilai, dan pengkompilasi menghasilkan semua anggota kesetaraan yang diperlukan untuk Anda.
Note
String adalah kelas, tetapi == dan Equals membandingkan konten string, bukan identitas.
-
==: operator kesetaraan. Kebanyakan tipe menggunakan operator ini sebagai cara utama untuk memeriksa kesetaraan. Perilakunya bergantung pada apakah tipe tersebut memiliki operator==bawaan atau yang ditentukan pengguna. -
!=: operator pertidaksamaan. Saat suatu tipe menentukan operator yang didefinisikan pengguna==, tipe tersebut juga harus menentukan!=. - Equals: metode virtual yang diwarisi oleh setiap tipe. Anda dapat meng-override-nya untuk mengubah semantik kesetaraan suatu tipe.
- GetHashCode: metode virtual yang digunakan oleh koleksi berbasis hash. Ketika dua nilai sama, kode hashnya juga harus sama.
- ReferenceEquals: metode statis yang selalu menguji identitas.
Menggunakan rekaman untuk kesetaraan nilai
Gunakan modifier record untuk memberikan kesetaraan nilai berbasis data pada tipe saat tipe tersebut dapat berupa record. Pengkompilasi menghasilkan anggota Equals, GetHashCode, dan ==/!= yang membandingkan setiap nilai properti yang dideklarasikan.
record class masih merupakan jenis referensi, tetapi membandingkan nilai alih-alih identitas:
var person1 = new Person("Ada", "Lovelace");
var person2 = new Person("Ada", "Lovelace");
Console.WriteLine(person1 == person2); // => True
Console.WriteLine(person1.Equals(person2)); // => True
Console.WriteLine(ReferenceEquals(person1, person2)); // => False
ReferenceEquals mengonfirmasi bahwa person1 dan person2 merupakan objek yang berbeda dalam memori, sementara == dan Equals kembali True karena kesetaraan yang dihasilkan kompilator membandingkan nilai properti.
Generasi kompilator yang sama juga berlaku untuk tipe record struct:
var dim1 = new Dimension(1920, 1080);
var dim2 = new Dimension(1920, 1080);
Console.WriteLine(dim1 == dim2); // => True
Console.WriteLine(dim1.Equals(dim2)); // => True
Jenis catatan menghasilkan seluruh set kesetaraan untuk jenisnya sendiri. Baik tipe record class maupun record struct meng-override Equals dan GetHashCode. Mereka juga menghasilkan == operator dan != , ditambah metode yang ditik Equals untuk jenis catatan. Tidak seperti biasa struct, record struct oleh karena itu mendukung == dan != secara otomatis. Untuk informasi selengkapnya tentang jenis rekaman dan semantik kesetaraannya, lihat Rekaman.
Rekaman dengan anggota tipe referensi
Kesetaraan record menggunakan semantik kesetaraan milik anggotanya sendiri. Setiap properti atau bidang dibandingkan dengan menggunakan metodenya sendiri Equals . Untuk sebagian besar nilai skalar, seperti int, string, atau DateTime, pendekatan ini membandingkan nilai anggota record. Nuansanya muncul pada koleksi umum yang dapat dimodifikasi seperti List<T> atau T[]: tipe-tipe ini dibandingkan berdasarkan referensi, sehingga dua instance record yang berisi objek list yang berbeda dengan konten yang samatidak dianggap setara oleh kesetaraan record yang disintesis.
var playlist1 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
var playlist2 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
Console.WriteLine(playlist1.Equals(playlist2)); // => False (different List instances)
Console.WriteLine(playlist1.Tracks.SequenceEqual(playlist2.Tracks)); // => True
playlist1 dan playlist2 merupakan instans terpisah List<string> . Meskipun kontennya cocok, Equals mengembalikan false.
Jika Anda perlu agar kesetaraan record mencerminkan isi koleksi, ada beberapa opsi yang dapat dipilih:
-
Terapkan
IEquatable<T>pada record dan timpaEqualsagar menggunakan Enumerable.SequenceEqual untuk anggota koleksi. -
Gunakan tipe koleksi dengan kesamaan nilai — misalnya,
IEqualityComparer<T>kustom atau tipe yangEquals-nya sendiri membandingkan elemen. - Rancang berdasarkan identitas: jika record tersebut merepresentasikan entitas, bukan sekadar nilai murni, kesetaraan referensial untuk anggota koleksinya mungkin memang disengaja.
Important
Implementasi manual kesetaraan jarang terjadi saat ini di C#. Rekaman menangani skenario umum kesetaraan nilai secara otomatis. Jika Anda perlu menerapkan equalitas secara manual—misalnya, karena tipe Anda harus diturunkan dari kelas dasar non-record—lihat Menerapkan equalitas sendiri saat tipe tidak dapat berupa record di referensi bahasa.
Baca juga
- Gambaran umum sistem tipe
- Kelas
- Struktur
- Rekaman
- Tupel dan dekonstruksi.
- Operator kesetaraan (referensi bahasa).
- Kesetaraan dalam hierarki kelas - panduan lanjutan tentang kesetaraan polimorfik.
- Operator aritmatika, perbandingan, logis, dan penugasan — ikhtisar operator kesamaan beserta operator aritmatika, perbandingan, logis, dan penugasan.