Mastering Deconstruction in C# — Practical Guide & Examples
Deconstruction lets you unpack values from tuples and your own types into variables in a single, readable statement. This article covers everything from the basics to advanced patterns, with clear examples you can copy-and-run.
1. What is Deconstruction?
Deconstruction is a feature introduced in C# 7.0 that allows an object (commonly a tuple or any type that implements a Deconstruct
method) to be split directly into separate variables using the (a, b, ...)
syntax. Behind the scenes the compiler calls the Deconstruct
method (or uses tuple deconstruction) to produce the output values.
2. Deconstruction with Tuples
Tuples in C# have built-in deconstruction support. It's the simplest and most common use-case.
// Tuple creation and deconstruction (string name, int age) person = ("Alice", 25); var (personName, personAge) = person; Console.WriteLine($"{personName} is {personAge} years old.");
Using var
is common, but you can explicitly type the variables:
(string name, int age) = ("Bob", 30); // name is string, age is int
3. Deconstruction with Custom Types
To enable deconstruction on your own classes/structs, implement a Deconstruct
method that returns values via out
parameters. The method can be an instance method and can have multiple overloads.
public class Employee { public string Name { get; set; } public string Department { get; set; } public int Salary { get; set; } // Deconstruct method public void Deconstruct(out string name, out string dept, out int salary) { name = Name; dept = Department; salary = Salary; } } // Usage var emp = new Employee { Name = "John", Department = "IT", Salary = 50000 }; var (empName, empDept, empSalary) = emp; Console.WriteLine($"{empName} from {empDept} earns {empSalary}");
Note: Deconstruction is syntactic sugar — the compiler rewrites the deconstruction statement to a call to emp.Deconstruct(out ...)
.
4. Partial Deconstruction and Discards
If you only need some values you can use a discard (_
) for values you want to ignore:
var emp = new Employee { Name = "Mary", Department = "HR", Salary = 60000 }; var (empName, _, empSalary) = emp; // ignore Department Console.WriteLine($"{empName} earns {empSalary}");
Using _
makes your intent explicit — you don’t accidentally rely on ignored values later.
5. Multiple Deconstruct
Overloads
You can provide more than one Deconstruct
overload for different use-cases:
public void Deconstruct(out string name, out string dept) { name = Name; dept = Department; } // Then you can write: var (name, dept) = emp; // salary not extracted
This is handy when the full object has many properties but most call-sites need only a small subset.
6. Deconstruction in foreach
When iterating collections of tuples or objects that support deconstruction, you can deconstruct directly in the loop header:
var people = new List<(string Name, int Age)> { ("Alice", 25), ("Bob", 30) }; foreach (var (name, age) in people) { Console.WriteLine($"{name} is {age} years old."); }
7. Deconstruction and Pattern Matching
Deconstruction works well with is
and switch
pattern matching. You can combine deconstruction with conditional checks.
// Example using a tuple object o = ("John", "IT", 52000); if (o is (string name, string dept, var sal) && sal > 50000) { Console.WriteLine($"High-paid employee: {name} of {dept} earns {sal}"); }
For custom types you can deconstruct in an is
expression as well when the compiler can infer the Deconstruct call.
8. When (and When Not) to Use Deconstruct
- Use it when you need multiple properties at once and want concise code.
- Avoid when you need just one property — direct property access is clearer and cheaper to read.
- Don’t overuse deconstruction for large objects with many fields — it can reduce readability if the meaning of each variable is not obvious.
9. Best Practices
- Keep
Deconstruct
overloads small and focused (2–3 outputs is usually ideal). - Use descriptive variable names when deconstructing, not just
a, b, c
, unless context makes intent clear. - Prefer deconstruction in cases where it improves clarity (e.g., consuming tuple returns from helper methods).
- Document
Deconstruct
overloads so callers know what each element represents.
10. Complete Examples
Example A — Multiple Overloads and Usage
public class Point3D { public double X { get; set; } public double Y { get; set; } public double Z { get; set; } public void Deconstruct(out double x, out double y) { x = X; y = Y; } public void Deconstruct(out double x, out double y, out double z) { x = X; y = Y; z = Z; } } // Usage var p = new Point3D { X = 1, Y = 2, Z = 3 }; var (x, y) = p; // uses 2-value deconstruct var (x2, y2, z2) = p; // uses 3-value deconstruct
Example B — Returning Multiple Values from a Method
// Using tuples public (int sum, int diff) SumAndDiff(int a, int b) { return (a + b, a - b); } // Caller var (sum, diff) = SumAndDiff(10, 5); Console.WriteLine($"sum={sum}, diff={diff}");
Example C — Deconstruction with Pattern Matching
// Assume a custom type with Deconstruct(out string name, out string dept, out int sal) if (emp is { } && emp is ("John", var dept, var salary) && salary > 40000) { Console.WriteLine("Found John with high salary in " + dept); }
Summary
Deconstruction in C# is a small but powerful feature that improves readability when you need to extract multiple values from tuples or custom types. Implement Deconstruct
methods for your types to enable idiomatic, compact code—just follow best practices to keep your code clear.