C# Discard Pattern: Syntax and Practical Use Cases
c# discard pattern: Learn the C# discard pattern: how to use discards for out parameters, deconstruction, and pattern matching, plus common pitfalls.
When you call a method with an out parameter you don't need, you can use a discard to avoid declaring a variable. The C# discard pattern uses the underscore character _ as a placeholder for a value you intentionally want to ignore. This signals your intent to the compiler and to other developers, while avoiding the noise of unused variable declarations.
Discard Syntax and Basic Usage
A discard is written as _ in an assignment or parameter position. It is not a variable; it does not have a name and cannot be read from. The compiler treats it as a special kind of placeholder that discards the value assigned to it.
// Traditional way: declare a variable you never use int unused; if (int.TryParse("42", out unused)) { } // With discard: no variable declaration if (int.TryParse("42", out _)) { }
The second version is clearer: you only care whether the parse succeeded, not the parsed value. The discard makes that explicit.
Discards work in assignments as well:
_ = ComputeValue(); // The result is intentionally ignored
You can use multiple discards in the same statement, each represented by _.
Using Discards with Out Parameters
Methods that use out parameters often require you to pass a variable even when you don't need the output. Discards remove that requirement.
public bool TryGetConfiguration(out string connectionString, out int timeout) { // ... } // Only need the timeout if (TryGetConfiguration(out _, out int timeout)) { Console.WriteLine(timeout); }
This is especially useful when a method returns multiple out values but your current logic only needs a subset. Without discards, you'd have to declare dummy variables, which adds clutter and may trigger compiler warnings about unused variables.
Discards in Deconstruction
Deconstruction lets you split a tuple or a custom type into individual components. Often you only need some of those components. Discards let you skip the ones you don't care about.
var (name, _, score) = GetPlayerStats();
Here, the second component is ignored. The same pattern works with deconstruct methods on your own types:
public void Deconstruct(out string firstName, out string lastName, out int age) { // ... } var (first, _, _) = person;
Using discards in deconstruction keeps the code concise and shows which fields are relevant to the current operation.
Discards in Pattern Matching
Pattern matching in C# supports discards in several forms. In a switch expression or statement, you can use _ as a catch-all pattern that matches any value.
string Describe(object value) => value switch { int i => $"Integer: {i}", string s => $"String: {s}", _ => "Unknown type" };
The _ pattern matches everything that didn't match earlier patterns. It is the equivalent of a default case.
Discards also appear in property patterns and positional patterns when you want to ignore a specific part:
if (point is (0, _)) { Console.WriteLine("X is zero"); }
Here, the tuple pattern checks that X is zero and ignores Y. This is a compact way to test only part of a structure.
Performance and Runtime Considerations
Discards are a compile-time feature. They do not generate any special runtime instructions. Using _ instead of a named variable does not change the generated IL in most cases; the compiler simply optimizes away the unused storage. There is no performance penalty or benefit from using discards. The advantage is purely in code readability and maintainability.
One subtle point: if you use a discard in a deconstruct call, the compiler may still call the Deconstruct method and evaluate all components, even the ones you discard. The discard only affects how the result is stored, not whether the method executes. So if the Deconstruct method has side effects, they still occur. Keep this in mind when using discards with custom types.
Common Mistakes and Limitations
A common mistake is treating _ as a regular variable. In most contexts, _ is a discard, but you can also declare a variable named _ in the same scope. This can lead to confusion. For example:
int _ = 10; _ = 20; // This is a regular variable assignment, not a discard
When a variable named _ is in scope, using _ in a deconstruction or out parameter position may bind to that variable instead of acting as a discard, depending on the C# version and context. To avoid ambiguity, don't use _ as a variable name in code that also uses discards.
Another limitation: discards are not allowed in expression trees. Expression trees represent code as data, and they cannot represent the concept of a discard. If you try to use a discard inside an expression tree, you'll get a compile-time error. This matters for libraries that use expression trees, such as some ORMs or LINQ providers.
Finally, discards cannot be used as the target of a ref or out argument in all cases. The C# specification defines where discards are valid; for instance, you can use out _ but not ref _ in a method call that expects a ref parameter. Always verify the specific context.
Choosing When to Use Discards
Use a discard when you want to ignore a value and make that intention explicit. If you need to keep the value for later, use a named variable. Discards are particularly useful in test code, where you often call methods only for their side effects, and in glue code that interacts with APIs that return more data than you need.
Avoid overusing discards in public APIs or in code where the ignored value might be important later. If you discard a value now and later need it, you'll have to refactor. Discards are a signal that the value is intentionally not used, which is valuable for code review.
In summary, the C# discard pattern is a small but effective tool for writing cleaner, more expressive code. It reduces clutter, clarifies intent, and integrates well with modern C# features like deconstruction and pattern matching. Understanding where discards are valid and how they behave at runtime helps you apply them correctly in your projects.