.Net application development specialists
asp.net, c#, vb.net, html, javascript, jquery, html, xhtml, css, oop, design patterns, sql server, mvc and much more
contact: admin@paxium.co.uk

Paxium is the company owned by myself, Dave Amour and used for providing IT contract development services including


  • Application development - Desktop, Web, Services - with Classic ASP, Asp.net WebForms, Asp.net MVC, Asp.net Core
  • Html, Css, JavaScript, jQuery, React, C#, SQL Server, Ado.net, Entity Framework, NHibernate, TDD, WebApi, GIT, IIS
  • Database schema design, implementation & ETL activities
  • Website design and hosting including email hosting
  • Training - typically one to one sessions
  • Reverse Engineering and documentation of undocumented systems
  • Code Reviews
  • Performance Tuning
  • Located in Cannock, Staffordshire
Rugeley Chess Club Buying Butler Cuckooland Katmaid Pet Sitting Services Roland Garros 60 60 Golf cement Technical Conformity Goofy MaggieBears Vacc Track Find Your Smart Phone eBate Taylors Poultry Services Lafarge Rebates System Codemasters Grid Game eBate DOFF

C# Equality — Quick Revision Sheet

== vs Equals in C#

Equals(object)

  • From System.Object.
  • Virtual → can override.
  • Default: reference equality.
  • Overridden by many types for value equality, e.g.:
    • string
    • DateTime
    • decimal
    • All primitive value types (int, double, bool, etc.)
    • Collections (List<T>, Dictionary<K,V>, etc. — they check contained values in some operations)

==

  • Operator.
  • Default:
    • Reference types → reference equality
    • Value types → value equality
  • Overloaded for value equality in:
    • string
    • DateTime
    • decimal
    • Most primitives (int, double, bool, etc.)

Best practice for custom classes

  • Override Equals
  • Override GetHashCode
  • Overload == / != for consistency

⚡ Rule of thumb:

If not overridden → both check reference equality.
If overridden (e.g., string, DateTime) → compare contents/values.

What are we comparing?

  • Reference equality: are the two variables pointing to the same object instance?
  • Value equality: do the two variables represent the same value (same contents)?

By default, classes compare by reference; structs compare by value. Records are designed for value equality.

Operators & Methods

== vs Equals

  • Equals(object): virtual on System.Object. Default is reference equality; many types override to compare values.
  • ==: operator. Default is reference for reference types, value for value types. Can be overloaded.
// String overrides both:
    object o  = "Hello";
    object o1 = o;
    Console.WriteLine(o == o1);       // True (same ref)
    Console.WriteLine(o.Equals(o1));  // True (string value equality)
Defaults

Classes, Structs, Records

  • class Default: reference equality.
  • struct Default: value equality (field-by-field).
  • record Default: value equality (compiler generates Equals, GetHashCode, ==, !=).
public record Person(string Name, int Age);
    var a = new Person("Alice", 30);
    var b = new Person("Alice", 30);
    Console.WriteLine(a == b);      // True
    Console.WriteLine(a.Equals(b)); // True
Common overrides

Types that compare by value

  • All primitives: int, double, bool, etc.
  • string (ordinal by default, culture options via APIs).
  • DateTime, DateOnly, TimeOnly, TimeSpan.
  • decimal, Guid.
  • Most enums (underlying numeric equality).

Collections like List<T> don’t override ==; they use Equals from object (reference). Many collection operations use IEqualityComparer<T>/IEquatable<T> of the elements.

Template

Recommended pattern for custom classes

public sealed class Person : IEquatable<Person>
{
    public string Name { get; }
    public int Age { get; }

    public Person(string name, int age)
    {
        Name = name;
        Age  = age;
    }

    // Value equality on Name + Age
    public bool Equals(Person? other)
        => other is not null && Name == other.Name && Age == other.Age;

    public override bool Equals(object? obj) => obj is Person p && Equals(p);

    public override int GetHashCode() => HashCode.Combine(Name, Age);

    public static bool operator ==(Person? left, Person? right)
        => Equals(left, right);

    public static bool operator !=(Person? left, Person? right)
        => !Equals(left, right);
}

Always keep Equals, GetHashCode, and ==/!= consistent. If instances can be used as dictionary keys or in a HashSet, GetHashCode must align with Equals.

Gotchas

Things that trip people up

  • Override only one (e.g., just Equals) → inconsistent behavior with ==.
  • Null handling: prefer implementing IEquatable<T> and static operators that tolerate nulls.
  • Floating point: don’t compare with == if precision matters — use tolerances.
  • Strings: default equality is ordinal, case-sensitive. For culture-insensitive comparisons use StringComparer.OrdinalIgnoreCase.
Quick rules

Memorise these

  • Classes: default ref equality. Override for value semantics.
  • Structs: value equality out of the box.
  • Records: value equality generated by the compiler.
  • Equals is the framework’s contract; == is sugar — make them agree.