C#
object comparison
property differences
programming
.NET

Finding property differences between two C objects

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Comparing two C# objects property by property is a common requirement in auditing, synchronization, testing, and change tracking. The right approach depends on whether you care about a single type, many types, nested objects, or raw performance.

Manual comparison is best for small, important models

For a small domain type, explicit comparison is often the clearest solution.

csharp
1public record Person(string Name, int Age, string City);
2
3public static List<string> GetDifferences(Person left, Person right)
4{
5    var differences = new List<string>();
6
7    if (left.Name != right.Name)
8        differences.Add($"Name: '{left.Name}' vs '{right.Name}'");
9
10    if (left.Age != right.Age)
11        differences.Add($"Age: {left.Age} vs {right.Age}");
12
13    if (left.City != right.City)
14        differences.Add($"City: '{left.City}' vs '{right.City}'");
15
16    return differences;
17}

This is easy to debug and avoids reflection. It is also the best option when only a few properties matter or when different properties need different comparison rules.

Reflection is useful for generic comparison

If you need a reusable utility for many object types, reflection can inspect public properties dynamically.

csharp
1using System.Reflection;
2
3public static List<string> GetPropertyDifferences<T>(T left, T right)
4{
5    var differences = new List<string>();
6    var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
7
8    foreach (var property in properties)
9    {
10        var leftValue = property.GetValue(left);
11        var rightValue = property.GetValue(right);
12
13        if (!Equals(leftValue, rightValue))
14        {
15            differences.Add($"{property.Name}: '{leftValue}' vs '{rightValue}'");
16        }
17    }
18
19    return differences;
20}

This works well for simple objects with scalar properties. It is concise, but it comes with trade-offs:

  • slower than handwritten comparison
  • less control over formatting
  • shallow by default unless you recurse into child objects

Handling nested objects

If the object graph contains child objects or collections, a shallow comparison is usually not enough. You need to decide whether:

  • only top-level property values matter
  • nested objects should be compared recursively
  • collection order matters

For example, comparing two addresses as raw objects may only tell you that the Address property changed, not which field inside the address changed. Recursive comparison can improve detail, but it also raises questions about cycles, null handling, and performance.

For that reason, many teams use a library once the comparison rules become non-trivial.

Libraries can save time

For general-purpose object diffing in .NET, a library such as Compare-Net-Objects is often a better choice than building and debugging recursive reflection yourself. These tools usually handle:

  • nested objects
  • collections
  • null values
  • cyclic references
  • configurable property inclusion and exclusion

If the requirement is production-grade diffing across many model types, a library is usually cheaper than maintaining a homemade comparer.

When records or value equality help

If you are only asking whether two objects are equal, C# records already give you value-based equality:

csharp
1public record Person(string Name, int Age, string City);
2
3var a = new Person("Ada", 30, "London");
4var b = new Person("Ada", 31, "London");
5
6Console.WriteLine(a == b); // false

That does not produce a property-by-property diff, but it may eliminate the need for one in tests or validation code where a simple equal or not-equal answer is enough.

Choosing the right approach

Use manual comparison when the model is small and the output matters. Use reflection for lightweight reusable tooling. Use a library when object graphs are complex or the comparison rules need to scale across the codebase.

The mistake is assuming there is one "best" object diffing technique. The right choice depends on how much detail, speed, and reuse you need.

Common Pitfalls

  • Using reflection for a tiny object where manual comparison would be simpler and clearer.
  • Performing only shallow comparison when the real change is inside a nested object.
  • Comparing values by string conversion and accidentally losing type fidelity.
  • Forgetting null handling when reading property values through reflection.
  • Building a recursive comparer without protecting against cyclic object graphs.

Summary

  • Manual comparison is best for small, important models with custom rules.
  • Reflection is useful for generic property-by-property comparison across types.
  • Nested objects and collections quickly make homemade comparison more complex.
  • Libraries are often the right choice for deep or reusable object diffing.
  • If you only need equality, records and value-based comparison may already solve the problem.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.