[Everyday C#] Fundamentals: Equality comparisons#54849
Conversation
Add fundamentals concept article on object equality for classes, structs, records, and tuples. Covers value equality vs. reference equality, Equals/==/ReferenceEquals semantics, IEquatable<T> implementation pattern, and record compiler-generated equality. Backed by a net10.0 snippet project (0 warnings, 0 errors). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5dca83ef-a274-4737-96d5-a311bfe58550
Relocate the Equality fundamentals article and snippets from Type system to the new Expressions folder, and update the TOC and relative links for the new location. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bc6b7895-3b18-45ff-99de-540618819cb3
Clarify default equality behavior, operator terminology, and manual value equality guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bc6b7895-3b18-45ff-99de-540618819cb3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bc6b7895-3b18-45ff-99de-540618819cb3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bc6b7895-3b18-45ff-99de-540618819cb3
Deemphasize the value of IEquatable<T> throughout the article.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bc6b7895-3b18-45ff-99de-540618819cb3
There was a problem hiding this comment.
Pull request overview
Adds a new Everyday C# Fundamentals article that explains equality comparisons across common C# type categories, backed by a buildable snippet project, and wires the article into the C# TOC.
Changes:
- Adds a new article:
fundamentals/expressions/equality.md. - Adds a buildable snippet project under
fundamentals/expressions/snippets/equality/used by the article. - Updates the C# TOC to link the new article under Expressions and statements.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| docs/csharp/toc.yml | Adds a TOC entry for the new equality article. |
| docs/csharp/fundamentals/expressions/equality.md | Introduces the new equality comparisons article and references snippets. |
| docs/csharp/fundamentals/expressions/snippets/equality/Program.cs | Adds runnable examples demonstrating default equality behavior and IEquatable<T>. |
| docs/csharp/fundamentals/expressions/snippets/equality/equality.csproj | Adds a minimal project file to build and run the snippet code. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Run another edit pass on this PR.
This organization of the material works much better.
| > [!TIP] | ||
| > This article is part of the **Fundamentals** section for developers who already know at least one programming language and are learning C#. If you're new to programming, start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. | ||
| > | ||
| > **Coming from another language?** In Java, `==` on objects and JavaScript `===` on objects test identity, not content. C# classes work the same way by default. In Python, `==` calls `__eq__` and tests content by default - similar to how C# [records](../types/records.md) compare. C# [structs](../types/structs.md) also compare by value when you call `Equals`. |
There was a problem hiding this comment.
| > **Coming from another language?** In Java, `==` on objects and JavaScript `===` on objects test identity, not content. C# classes work the same way by default. In Python, `==` calls `__eq__` and tests content by default - similar to how C# [records](../types/records.md) compare. C# [structs](../types/structs.md) also compare by value when you call `Equals`. | |
| > **Coming from another language?** In Java, `==` on objects and JavaScript `===` on objects test identity, not content. C# classes work the same way by default. In Python, `==` calls `__eq__` and tests content by default , similar to how C# [records](../types/records.md) compare. C# [structs](../types/structs.md) also compare by value when you call `Equals`. |
Verrrrry minor. Hyphen used instead of a dash. Replaced witha comma since it seemed a bit better.
| - `==` - the equality operator. Most types use this as the primary equality check. Its behavior depends on whether the type has a built-in or user-defined `==` operator. | ||
| - `!=` - the inequality operator. When a type defines a user-defined `==` operator, it must also define `!=`. | ||
| - <xref:System.Object.Equals*> - a virtual method inherited by every type. You can override it to change equality semantics for a type. | ||
| - <xref:System.Object.GetHashCode*> - a virtual method used by hash-based collections. When two values are equal, their hash codes must also be equal. | ||
| - <xref:System.Object.ReferenceEquals*> - a static method that always tests identity. |
There was a problem hiding this comment.
| - `==` - the equality operator. Most types use this as the primary equality check. Its behavior depends on whether the type has a built-in or user-defined `==` operator. | |
| - `!=` - the inequality operator. When a type defines a user-defined `==` operator, it must also define `!=`. | |
| - <xref:System.Object.Equals*> - a virtual method inherited by every type. You can override it to change equality semantics for a type. | |
| - <xref:System.Object.GetHashCode*> - a virtual method used by hash-based collections. When two values are equal, their hash codes must also be equal. | |
| - <xref:System.Object.ReferenceEquals*> - a static method that always tests identity. | |
| - `==`: the equality operator. Most types use this as the primary equality check. Its behavior depends on whether the type has a built-in or user-defined `==` operator. | |
| - `!=`: the inequality operator. When a type defines a user-defined `==` operator, it must also define `!=`. | |
| - <xref:System.Object.Equals*>: a virtual method inherited by every type. You can override it to change equality semantics for a type. | |
| - <xref:System.Object.GetHashCode*>: a virtual method used by hash-based collections. When two values are equal, their hash codes must also be equal. | |
| - <xref:System.Object.ReferenceEquals*>: a static method that always tests identity. |
Verry minor, you could take or leave. Hyphen used instead of dash. A colon seems better to me then a dash as a common term-definiton seperator.
| > [!IMPORTANT] | ||
| > This section shows how to implement by hand the equality behavior that the compiler generates when you add `record` to a type. If your type can be a record, use `record` instead. It generates all these members for you. Implement them manually only when your type can't be a record. | ||
|
|
||
| When a class or struct represents a value, such as a color or a measurement, the equality members for that type must agree. The easiest way to achieve this consistency is to declare the type as a `record`. If the type can't be a record, such as when it must derive from a non-record class, implement the equality members yourself. The language enforces that user-defined `==` and `!=` operators must be declared as a pair. If you provide those operators, compiler warning [CS0660](../../language-reference/compiler-messages/overloaded-operator-errors.md#equality-operators) means the type also needs an <xref:System.Object.Equals*?displayProperty=nameWithType> override. Warning [CS0661](../../language-reference/compiler-messages/overloaded-operator-errors.md#equality-operators) means the type also needs an <xref:System.Object.GetHashCode?displayProperty=nameWithType> override. |
There was a problem hiding this comment.
| When a class or struct represents a value, such as a color or a measurement, the equality members for that type must agree. The easiest way to achieve this consistency is to declare the type as a `record`. If the type can't be a record, such as when it must derive from a non-record class, implement the equality members yourself. The language enforces that user-defined `==` and `!=` operators must be declared as a pair. If you provide those operators, compiler warning [CS0660](../../language-reference/compiler-messages/overloaded-operator-errors.md#equality-operators) means the type also needs an <xref:System.Object.Equals*?displayProperty=nameWithType> override. Warning [CS0661](../../language-reference/compiler-messages/overloaded-operator-errors.md#equality-operators) means the type also needs an <xref:System.Object.GetHashCode?displayProperty=nameWithType> override. | |
| When a class or struct represents a value, such as a color or a measurement, the equality members for that type must agree. The easiest way to achieve this consistency is to declare the type as a `record`. If the type can't be a record, such as when it must derive from a non-record class, implement the equality members yourself. The language enforces that user-defined `==` and `!=` operators must be declared as a pair. If you provide those operators, compiler warning [CS0660](../../language-reference/compiler-messages/overloaded-operator-errors.md#equality-operators) means the type also needs an <xref:System.Object.Equals*?displayProperty=nameWithType> override. Warning [CS0661](../../language-reference/compiler-messages/overloaded-operator-errors.md#equality-operators) means the type also needs an <xref:System.Object.GetHashCode*?displayProperty=nameWithType> override. |
Minor: The first link used * to resolve to the overload page I think. The last one did not. Was the asterisk missing on the last one here? xref:System.Object.GetHashCode*?
wadepickett
left a comment
There was a problem hiding this comment.
@BillWagner: Approved, great work! See my few very minor suggestions inline that you could take or leave.
Closes #54112
Phase E / PR 14b of the Everyday C# Fundamentals restructuring.
Summary:
docs/csharp/fundamentals/expressions/equality.mdin the newfundamentals/expressions/folder, added to the TOC under "Expressions and statements".==,!=,Equals,GetHashCode,ReferenceEquals), and how to add value equality by hand (with a record-first IMPORTANT callout).snippets/equality/), verifieddotnet build0 warnings/0 errors on net10.0 withdotnet runoutput matching the article.operators.mdis intentionally deferred to PR 16 and is not included here.Internal previews