Back to Blog
C#

C# Discard Lambda Parameter: When and How to Use It

c# discard lambda parameter: Learn how to use the C# discard `_` for lambda parameters, why it improves clarity, and where it works in delegates, LINQ, and event handl...

C#Lambda ExpressionsDiscardsDelegatesLINQCode Clarity
Illustration of a C# lambda expression using an underscore discard for an unused parameter.

Using _ as a lambda parameter is a common C# idiom that tells the compiler and other developers that the parameter is intentionally unused. The c# discard lambda parameter feature, introduced with C# 7.0, is a syntactic convenience that reduces noise in code where a delegate signature requires a parameter you do not need. It also prevents compiler warnings about unused variables and makes the intent explicit.

The Syntax of a Discard Lambda Parameter

A discard is represented by the underscore character _. When used as a lambda parameter, it indicates that the parameter exists only to satisfy the delegate signature. The compiler treats _ as a special placeholder that cannot be read or used inside the lambda body.

Func<int, int, int> add = (a, _) => a + 10; // second parameter is discarded

In this example, the second parameter is ignored. The lambda still accepts two arguments, but only the first is used. You can also discard all parameters:

Action<int, string> log = (_, _) => Console.WriteLine("Log entry");

Each _ is an independent discard. Multiple discards in the same lambda are allowed, and each one represents a separate unused parameter.

Why Use a Discard Instead of a Named Parameter

Before discards, developers often named unused parameters with a leading underscore or some placeholder like unused. This approach had two problems. First, it left a named variable that could accidentally be referenced later, creating subtle bugs. Second, it triggered compiler warnings about unused variables unless the name started with an underscore, which is a convention but not enforced by the compiler.

A discard removes both issues. The parameter cannot be referenced, so there is no risk of accidental use. The compiler does not warn about unused discards because they are designed to be ignored. This makes the code's intent clear: the parameter is irrelevant to the operation.

Common Scenarios: Event Handlers and Delegates

Event handlers often have a signature with parameters that you do not need. For example, a button click handler receives sender and EventArgs, but you may only care that the click happened. Using discards keeps the handler concise.

button.Click += (_, _) => StartProcessing();

Here, both parameters are discarded because the handler does not use them. This is clearer than writing (object sender, EventArgs e) and then not using them. The same applies to custom delegates where you must match a signature but only need a subset of the arguments.

public delegate void ProgressHandler(int percent, string status); ProgressHandler onProgress = (_, status) => Console.WriteLine(status);

Discards in LINQ and Collection Operations

LINQ methods often provide an index parameter that you do not need. For instance, Select has an overload that supplies the element index. If you only need the element itself, you can discard the index.

var doubled = numbers.Select((n, _) => n * 2);

Similarly, Where with an index can discard it:

var even = numbers.Where((n, _) => n % 2 == 0);

Discards also work in ForEach when you need to iterate but ignore the element. However, List<T>.ForEach expects an Action<T>, so you can write list.ForEach(_ => Console.WriteLine("Item")) to ignore the element entirely. This is useful when the iteration itself has side effects that do not depend on the current item.

What Discards Are Not: Limitations and Pitfalls

A discard is not a variable. You cannot read its value, pass it as an argument, or use it in an expression. The following code does not compile:

Func<int, int> f = _ => _ + 1; // error: cannot use discard as variable

This is intentional. The discard exists solely to satisfy the parameter list. Attempting to use it produces a compile-time error, which prevents accidental misuse.

Another limitation is that _ is not always a discard. In a lambda parameter list, _ is always a discard, but outside of that context, _ can be a regular identifier. This can lead to confusion if you have a variable named _ in scope. For example:

int _ = 5; Func<int, int> f = _ => _ + 1; // error: _ is a discard, not the variable

In the lambda, _ is treated as a discard, so the body cannot reference it. To use the outer variable, you would need to give the lambda parameter a different name. This is a subtle pitfall that can confuse developers unfamiliar with discards.

Maintainability and Code Clarity Considerations

Using discards improves readability when the parameter is genuinely unused, but overusing them can harm clarity. If a parameter is unused now but might be used later, a named parameter may be more appropriate. A discard signals that the parameter is permanently irrelevant, which can mislead future maintainers if the delegate signature changes.

Consider the tradeoff in each case. For a one-off event handler where you never expect to use the sender, a discard is fine. For a method that might need the parameter in the next iteration, a named parameter with a comment might be better. The compiler will not warn about an unused named parameter if you prefix it with an underscore, but that is a convention, not a language feature.

Discards also have zero runtime cost. They are purely compile-time constructs; the generated IL does not allocate or store the discarded value. This means you can use them freely without worrying about performance overhead. The only cost is the clarity benefit or drawback, which depends on how well the discard matches the actual intent of the code.

Compatibility and Version Requirements

Discards were introduced in C# 7.0 and are available in all later versions. If you are targeting an older compiler, you cannot use them. Most modern .NET projects use C# 7.0 or later, so this is rarely a constraint. However, if you are maintaining legacy code with an older language version, you will need to use named parameters or a different pattern.

When using discards, be aware that the _ character is also used for other purposes, such as a wildcard in pattern matching or a discard in out parameters. The same syntax applies, but the context determines the meaning. In a lambda parameter list, it is always a discard.

Choosing Between Discard and Named Parameter

Use a discard when the parameter is not used and will not be used in the foreseeable future. Use a named parameter when the parameter might be used later, or when the parameter name carries information that helps explain the lambda's behavior. For example, in a LINQ Select that uses the index, a discard is appropriate if you ignore the index. But if you plan to use the index in a future change, naming it index makes the code more self-documenting.

A practical rule is to prefer discards for parameters that are part of a delegate signature but irrelevant to the operation. For parameters that are relevant to the operation's logic, even if currently unused, a named parameter with a comment is safer. This keeps the code honest about its future intentions and avoids forcing a rename when the parameter becomes necessary.

c# discard lambda parameter: Practical Usage and Code Exampl | RYUSLOG DEV