Every way to compare two values
==, Equals, records, strings, IEquatable
First ask what kind of type you have, because that decides what ==
does before you've written a line.
- Numbers,
bool,char, enums →==compares the values. Fordouble, compare within a tolerance, not with==. string→==compares the characters, case and all. For user input and keys, say which rule you mean:string.Equals(a, b, StringComparison.OrdinalIgnoreCase).- A record →
==compares every property. That's usually what you want for data. - A class →
==asks "is this the same object?". Two separateCustomerobjects with the same email are not equal unless the class overridesEqualsandGetHashCode(or implementsIEquatable<T>). - You need an order, not just equal or not (sort products by
price) →
IComparable<T>on the type, or a key with LINQ'sOrderBywhen the order depends on the situation. - A dictionary or set should treat keys differently (ignore
case in usernames) → pass a comparer when you create it:
new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase).
If you override Equals, override GetHashCode too, or dictionaries
and HashSet<T> will lose your objects.
The rule, by kind of type
Formal. For classes, == and the default Equals compare
references (the same object) unless the class overloads them. string
overloads == to compare contents ordinally. Records (class and struct)
get compiler-generated value equality: equal when every member is
equal, comparing reference-type members by their own equality. A plain
struct has a field-by-field Equals but no == operator unless it
declares one.
In plain English. For most objects, "equal" means "the very same object", not "the same data". Strings and records are the exceptions you use most: two strings with the same letters are equal, and two records holding the same values are equal.
Example. new Point(1, 2) == new Point(1, 2) is true for
record Point(int X, int Y) and false for an ordinary class Point.
Why this rule exists. Identity matters for things like accounts and windows; value matters for data like coordinates and money. C# makes you pick by picking the kind of type.
Value types and records compare contents; classes compare references unless they say otherwise.
Section
Equals, GetHashCode and ==
What every type inherits from object, and what to override to change "equal".
Section
Records compare their values
The compiler writes Equals, GetHashCode and == for you, from the properties.
Text
Section
Comparing strings
Ordinal or culture-aware, with or without case, and the rule of thumb for choosing.
Section
Keys that ignore case
A comparer passed to the dictionary's constructor changes what counts as the same key.
Equality and order you define
Section
IEquatable and IComparable
A typed Equals that HashSet and Dictionary can use, and a natural sort order for Sort and OrderBy.
Section
OrderBy, ThenBy and sorting text
Sort by a key you choose at the call, with tie-breakers, instead of building the order into the type.
The set operators decide "same item" by the type's equality, or by a comparer you pass.