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.
Operator ==(persamaan) dan != (ketidaksetaraan) memeriksa apakah operan mereka sama atau tidak. Jenis nilai sama ketika kontennya sama. Jenis referensi sama ketika dua variabel merujuk ke penyimpanan yang sama.
Referensi bahasa C# mendokumentasikan versi bahasa C# yang paling baru dirilis. Ini juga berisi dokumentasi awal untuk fitur dalam pratinjau publik untuk rilis bahasa yang akan datang.
Dokumentasi mengidentifikasi fitur apa pun yang pertama kali diperkenalkan dalam tiga versi terakhir bahasa atau dalam pratinjau publik saat ini.
Petunjuk / Saran
Untuk menemukan kapan fitur pertama kali diperkenalkan di C#, lihat artikel tentang riwayat versi bahasa C#.
Anda dapat menggunakan is operator pencocokan pola sebagai alternatif untuk == pengujian saat menguji terhadap nilai konstanta. Operator is menggunakan semantik kesetaraan default untuk semua nilai dan jenis referensi.
Operator Persamaan ==
Operator persamaan ==mengembalikantrue jika operannya sama, false jika tidak.
Persamaan jenis nilai
Operand dari tipe nilai bawaan adalah sama jika nilainya sama:
int a = 1 + 2 + 3;
int b = 6;
Console.WriteLine(a == b); // output: True
char c1 = 'a';
char c2 = 'A';
Console.WriteLine(c1 == c2); // output: False
Console.WriteLine(c1 == char.ToLower(c2)); // output: True
Catatan
==Untuk operator , , <>, <=, dan >= , jika salah satu operand bukan angka (Double.NaN atau Single.NaN), hasil operasinya adalah false. Kondisi itu NaN berarti bahwa nilainya tidak lebih besar dari, kurang dari, atau sama dengan nilai (atau double) lainnya float , termasuk NaN. Untuk informasi dan contoh yang lebih lengkap, lihat artikel referensi Double.NaN dan Single.NaN.
Dua operan dari tipe enum yang sama adalah sama jika nilai yang sesuai dari tipe integral yang mendasarinya sama.
Jenis struct yang ditentukan pengguna tidak mendukung operator == secara default. Untuk mendukung operator ==, struct yang ditentukan pengguna harus membebaninya.
Tuple C# memiliki dukungan bawaan == untuk operator dan != . Untuk informasi selengkapnya, lihat bagian Persamaan tuple dari artikel Jenis tuple.
Persamaan jenis referensi
Secara default, operand jenis referensi, tidak termasuk rekaman, sama jika merujuk ke objek yang sama:
public class ReferenceTypesEquality
{
public class MyClass
{
private int id;
public MyClass(int id) => this.id = id;
}
public static void Main()
{
var a = new MyClass(1);
var b = new MyClass(1);
var c = a;
Console.WriteLine(a == b); // output: False
Console.WriteLine(a == c); // output: True
}
}
Seperti yang ditunjukkan contoh sebelumnya, jenis referensi yang ditentukan pengguna mendukung == operator secara default. Namun, jenis referensi dapat membebani operator == secara berlebihan. Jika jenis referensi membebani operator ==, gunakan metode Object.ReferenceEquals untuk memeriksa apakah dua referensi jenis tersebut merujuk ke objek yang sama.
Persamaan jenis catatan
Jenis rekaman mendukung == operator dan != yang secara default memberikan semantik kesetaraan nilai. Artinya, dua operand rekaman sama ketika keduanya adalah atau nilai yang null sesuai dari semua bidang dan properti yang diimplementasikan secara otomatis sama.
public class RecordTypesEquality
{
public record Point(int X, int Y, string Name);
public record TaggedNumber(int Number, List<string> Tags);
public static void Main()
{
var p1 = new Point(2, 3, "A");
var p2 = new Point(1, 3, "B");
var p3 = new Point(2, 3, "A");
Console.WriteLine(p1 == p2); // output: False
Console.WriteLine(p1 == p3); // output: True
var n1 = new TaggedNumber(2, new List<string>() { "A" });
var n2 = new TaggedNumber(2, new List<string>() { "A" });
Console.WriteLine(n1 == n2); // output: False
}
}
Seperti yang ditunjukkan oleh contoh sebelumnya, kesetaraan anggota jenis referensi dibandingkan menggunakan implementasi kesetaraan spesifik mereka.
Persamaan string
Dua operan string sama jika keduanya null atau kedua instance string memiliki panjang yang sama dan memiliki karakter yang identik di setiap posisi karakter:
string s1 = "hello!";
string s2 = "HeLLo!";
Console.WriteLine(s1 == s2.ToLower()); // output: True
string s3 = "Hello!";
Console.WriteLine(s1 == s3); // output: False
Perbandingan kesetaraan string adalah perbandingan ordinal peka huruf besar/kecil. Untuk informasi selengkapnya tentang perbandingan string, lihatlah Cara membandingkan string di C#.
Menyatakan persamaan
Dua operan delegasi dengan jenis run-time yang sama sama ketika keduanya adalah null atau daftar pemanggilannya memiliki panjang yang sama dan memiliki entri yang sama di setiap posisi:
Action a = () => Console.WriteLine("a");
Action b = a + a;
Action c = a + a;
Console.WriteLine(object.ReferenceEquals(b, c)); // output: False
Console.WriteLine(b == c); // output: True
Penting
Entri yang sama dalam daftar pemanggilan mencakup semua parameter tetap dalam pemanggilan, termasuk penerima. Penerima adalah instans objek yang diwakili oleh this ketika entri dipanggil.
var o1 = new object();
var o2 = new object();
var d1 = o1.ToString;
var d2 = o2.ToString;
Console.WriteLine(object.ReferenceEquals(d1, d2)); // output: False
Console.WriteLine(d1 == d2); // output: False (different receivers)
Untuk informasi selengkapnya, lihat bagian Operator delegasi persamaan dari Spesifikasi bahasa C#.
Delegasi yang berasal dari mengevaluasi ekspresi lambda yang identik secara semantik tidak sama, seperti yang ditunjukkan contoh berikut:
Action a = () => Console.WriteLine("a");
Action b = () => Console.WriteLine("a");
Console.WriteLine(a == b); // output: False
Console.WriteLine(a + b == a + b); // output: True
Console.WriteLine(b + a == a + b); // output: False
Operator ketidaksamaan !=
Operator ketidaksetaraan != mengembalikan true jika operand-nya tidak sama, dan false sebaliknya. Untuk operand dari jenis bawaan, ekspresi x != y menghasilkan hasil yang sama dengan ekspresi !(x == y). Untuk informasi lebih lengkap tentang persamaan jenis, lihat bagian Operator persamaan.
Contoh berikut menunjukkan cara menggunakan != operator:
int a = 1 + 1 + 2 + 3;
int b = 6;
Console.WriteLine(a != b); // output: True
string s1 = "Hello";
string s2 = "Hello";
Console.WriteLine(s1 != s2); // output: False
object o1 = 1;
object o2 = 1;
Console.WriteLine(o1 != o2); // output: True
Kesetaraan dalam hierarki kelas
Rekaman menangani pewarisan dengan benar tanpa pekerjaan manual. Kesetaraan yang dihasilkan kompilator memeriksa jenis runtime dan semua properti yang dideklarasikan, sehingga secara otomatis memenuhi persyaratan simetri dan transitivitas. Lebih suka record hierarki manual yang tidak disegel ketika kesetaraan nilai adalah tujuannya.
Penting
Gunakan record jika memungkinkan — pengkompilasi menghasilkan semua anggota kesetaraan yang diperlukan untuk Anda. Implementasi manual hanya diperlukan ketika jenis Anda harus berasal dari kelas non-rekaman atau memiliki batasan lain yang mencegah record.
Terapkan kesetaraan sendiri ketika tipe tidak dapat menjadi record
Berikut adalah implementasi manual minimal untuk jenis nilai yang tidak dapat menjadi catatan:
class Color : IEquatable<Color>
{
public Color(int r, int g, int b)
{
R = r;
G = g;
B = b;
}
public int R { get; }
public int G { get; }
public int B { get; }
public bool Equals(Color? other) =>
other is not null && R == other.R && G == other.G && B == other.B;
public override bool Equals(object? obj) => obj is Color other && Equals(other);
public override int GetHashCode() => HashCode.Combine(R, G, B);
}
Implementasi ini menyediakan tiga anggota yang diperlukan: Equals(T?) sebagai perbandingan inti, override Equals(object?) untuk panggilan tingkat objek, sehingga override GetHashCode() koleksi berbasis hash berfungsi dengan benar.
HashCode.Combine adalah pembantu pustaka yang membangun satu hash dari nilai yang sama yang digunakan oleh Equals.
IEquatable<T> Menerapkan (Equals(T?)kelebihan beban) bersifat opsional tetapi menghindari tinju ketika penelepon sudah memiliki jenis beton.
Ketika Anda juga menentukan == dan !=, bahasa mengharuskannya sebagai pasangan; peringatan CS0660 dan CS0661 mengingatkan Anda untuk menjaga keempat anggota tetap konsisten.
Dengan tiga anggota di atas di tempat, Equals mencerminkan kesetaraan nilai, tetapi == masih menguji identitas karena belum ada == operator yang dinyatakan:
var red1 = new Color(255, 0, 0);
var red2 = new Color(255, 0, 0);
Console.WriteLine(red1.Equals(red2)); // => True
Console.WriteLine(red1 == red2); // => False (no == overload; identity check)
Implementasi yang benar juga harus memenuhi kontrak kesetaraan (asumsikan x, y, dan z non-null):
-
Refleksif
true:x.Equals(x)mengembalikan . -
Simetris:
x.Equals(y)mengembalikan nilai yang sama dengany.Equals(x). -
Transitif: jika
x.Equals(y)dany.Equals(z)keduanyatrue, makax.Equals(z)harustrue. -
Konsisten: panggilan berturut-turut untuk
x.Equals(y)mengembalikan nilai yang sama selama tidak ada objek yang berubah. -
Perilaku null:
x.Equals(null)mengembalikanfalse;x.Equals(y)tidak boleh dilemparkan ketika dipanggil pada non-nullx.
Kesetaraan nilai dalam hierarki kelas yang tidak tersegel membutuhkan lebih banyak perawatan daripada di kelas tertutup untuk memenuhi aturan simetris dan transitif. Bahayanya adalah bahwa pengiriman mengikuti jenis yang IEquatable<T>.Equals(T? other)dideklarasikan (jenis yang ditulis dalam deklarasi variabel) dari variabel, bukan jenis runtime-nya. Jika Shape mendeklarasikan non-, variabel yang diketik sebagai Shape yang memegang Circle pada waktu proses memanggil —mengabaikan Circlebidang -spesifik secara diam-diamEquals(Shape? other)virtualShape.Equals. Dua Circle objek dengan radii yang berbeda dapat dibandingkan sebagai sama ketika diakses melalui Shape variabel.
Pola yang benar memerlukan dua persyaratan yang bekerja sama: membuat metode yang ditik Equals sehingga setiap kelas turunan dapat memperpanjang perbandingan, dan menambahkan GetType() == other.GetType() penjaga dalam implementasi kelas dasar sehingga objek dari jenis runtime yang berbeda tidak pernah dianggap sama.virtual
Implementasi kelas dasar
// Shape is an unsealed base class. Making Equals virtual and guarding with GetType()
// ensures a derived instance is never equal to an instance of a different runtime type.
class Shape : IEquatable<Shape>
{
public string Color { get; }
public Shape(string color) => Color = color;
public override bool Equals(object? obj) => Equals(obj as Shape);
// virtual so derived classes can override and augment the comparison
public virtual bool Equals(Shape? other) =>
other is not null &&
GetType() == other.GetType() && // reject different runtime types
Color == other.Color;
// GetType() is included because equality requires matching runtime types
public override int GetHashCode() => HashCode.Combine(GetType(), Color);
public static bool operator ==(Shape? l, Shape? r) => l?.Equals(r) ?? r is null;
public static bool operator !=(Shape? l, Shape? r) => !(l == r);
}
Poin-poin penting:
- typed : setiap kelas turunan mengambil alih metode ini untuk menambah perbandingan
Equalsdengan bidangnya sendiri.virtual -
GetType()guard:GetType() == other.GetType()mencegah agarCircletidak samaShapedengan warna yang sama, dan mencegah objek dari berbagai jenis turunan agar tidak sama satu sama lain. -
GetHashCodetermasukGetType(): karena dua objek sama hanya ketika jenis runtimenya cocok,GetHashCodeharus hash jenis runtime serta bidang data. MenghilangkanGetType()di sini menyebabkan perilaku yang salah diDictionary<TKey,TValue>danHashSet<T>. -
==mendelegasikan keEquals: menjaga operator dan kesetaraan metode tetap konsisten.
Implementasi kelas turunan
Kelas turunan yang menambahkan bidang mengambil alih jenis , ditransmisikan Equalske jenisnya sendiri, panggilan base.Equals, lalu membandingkan bidangnya sendiri:
class Circle : Shape
{
public double Radius { get; }
public Circle(string color, double radius) : base(color) => Radius = radius;
public override bool Equals(object? obj) => Equals(obj as Shape);
// Calls base.Equals to verify Color and runtime type, then adds Radius
public override bool Equals(Shape? other) =>
other is Circle c && base.Equals(c) && Radius == c.Radius;
public override int GetHashCode() => HashCode.Combine(GetType(), Color, Radius);
}
base.Equals(c) memberlakukan GetType() penjaga dan memeriksa bidang bersama. Transmisi melalui other is Circle c gagal dengan cepat ketika argumen adalah Shape jenis turunan lainnya.
Penggunaan melalui variabel jenis dasar
Shape circle1 = new Circle("red", 5.0);
Shape circle2 = new Circle("red", 7.0);
Shape circle3 = new Circle("red", 5.0);
Shape shape1 = new Shape("red");
Console.WriteLine(circle1.Equals(circle2)); // => False (Radius differs)
Console.WriteLine(circle1.Equals(circle3)); // => True
Console.WriteLine(circle1.Equals(shape1)); // => False (different runtime types)
Kelas yang disegel lebih sederhana
Anda tidak dapat mensubkelas sealed kelas, jadi jenis waktu kompilasi dan runtime selalu setuju. Anda tidak perlu GetType() penjaga atau virtual pengiriman. Pola yang IEquatable<T> ditampilkan dalam Menerapkan kesetaraan sendiri ketika jenis tidak dapat menjadi rekaman sudah benar dan lengkap untuk kelas yang disegel.
Kelebihan beban operator
Anda dapat membebani== operator dan != dalam jenis yang ditentukan pengguna. Jika Anda membebani salah satu dari dua operator ini, Anda juga harus membebani operator lain.
Anda tidak dapat secara eksplisit membebani == operator dan != dalam jenis rekaman. Untuk mengubah perilaku == operator dan != untuk jenis Tcatatan , terapkan IEquatable<T>.Equals metode dengan tanda tangan berikut:
public virtual bool Equals(T? other);
Spesifikasi bahasa C#
Untuk informasi selengkapnya, lihatlah bagian Operator relasional dan pengujian jenis dari spesifikasi bahasa C#.
Untuk informasi selengkapnya tentang kesetaraan jenis rekaman, lihat bagian Anggota kesetaraandari spesifikasi bahasa C#.