C# tutorials > Modern C# Features > C# 6.0 and Later > What are discards (`_`) and how are they used?

What are discards (`_`) and how are they used?

Discards, introduced in C# 7.0, are write-only variables that you can assign values to when you don't intend to use those values. They are represented by the underscore character (_). Discards are particularly useful when deconstructing tuples or objects, ignoring out parameters from methods, and when handling events. This tutorial explores the concept of discards, their use cases, and provides practical examples.

Basic Discard Usage

The underscore (_) acts as a discard. In the first example, when deconstructing a tuple, the second element (person's name) is assigned to the discard, effectively ignoring it. In the second example, the TryParse method requires an out parameter, but the parsed integer value isn't needed; therefore, it's assigned to a discard. The TryParse still executes, verifying if the conversion is successful, but the parsed value is ignored.

// Example of using discards with tuples
(int age, string _, string city) = GetPersonInfo(); // Ignoring the person's name
Console.WriteLine($"Age: {age}, City: {city}");

// Example of using discards with out parameters
if (int.TryParse("123", out _))
{
    Console.WriteLine("Successfully parsed an integer, but its value is discarded.");
}

Concepts Behind the Snippet

Discards help improve code readability by explicitly stating that certain values are deliberately not used. They also prevent compiler warnings about unused variables, which would otherwise occur if you declared a variable but never used it. The compiler treats discards specially; it doesn't allocate memory for them. Each discard is effectively the same single storage location.

Real-Life Use Case Section

Consider a scenario where you subscribe to an event, but you only need to know that the event occurred, not who raised the event (the sender). The event handler requires a sender parameter, but if you don't use it, you can use a discard to indicate this intentionally. The provided code shows a DataReceived event. The event handler OnDataReceived ignores the sender (object sender) using a discard because it only cares that the event occurred, not about the object that raised it.

//Ignoring event sender.
public class MyClass
{
    public event EventHandler DataReceived;

    public void SimulateDataReception()
    {
        DataReceived?.Invoke(this, EventArgs.Empty);
    }
}

public class ConsumerClass
{
    public ConsumerClass(MyClass myObject)
    {
        myObject.DataReceived += OnDataReceived;
    }

    private void OnDataReceived(object _ , EventArgs e)
    {
        Console.WriteLine("Data received!");
    }
}

Best Practices

Use discards judiciously. Only use them when you genuinely don't need the value. Overuse can sometimes make the code harder to understand. Ensure that the discard's purpose is clear from the context. For instance, a clear method name or surrounding code should suggest why a value is being discarded. Avoid using discards as placeholders for variables you *might* use later. If there's a chance you'll need the value, declare a proper variable.

Interview Tip

Be prepared to explain the benefits of using discards over simply ignoring a variable. Emphasize the improved readability and the prevention of compiler warnings. Also, know that discards don't allocate memory, making them slightly more efficient. Show that you understand when and where to use discards appropriately, especially in scenarios like tuple deconstruction, out parameters, and event handling.

When to use them

Use discards in the following situations:
  • Tuple Deconstruction: When you only need some values from a tuple.
  • Out Parameters: When a method requires an out parameter, but you don't need the returned value.
  • Event Handlers: When you only care about the event occurring and not the sender.
  • Pattern Matching: To ignore values during pattern matching.

Memory Footprint

Discards are designed to have minimal impact on memory. The compiler treats all discards as the same storage location, so using multiple discards in a single scope doesn't result in multiple memory allocations. This makes them efficient when dealing with values you explicitly don't need.

Alternatives

Before discards, developers often used unused variables named unused, dummy, or something similar. While these worked, they didn't explicitly convey the intent of *discarding* the value. They also could trigger compiler warnings if the variable wasn't used. Another alternative, especially for out parameters, is to simply not call the method at all if you don't need the output. However, this is only possible if the method's side effects are not required.

Pros

  • Improved Readability: Clearly indicates that a value is intentionally not used.
  • Compiler Warning Suppression: Prevents warnings about unused variables.
  • Memory Efficiency: Discards do not allocate new memory locations.
  • Conciseness: Simplifies code, especially when deconstructing tuples or handling out parameters.

Cons

  • Potential for Misuse: If overused or used inappropriately, it can make code harder to understand.
  • Requires C# 7.0 or Later: Discards are not available in older versions of C#.

FAQ

  • Can I use multiple discards in the same scope?

    Yes, you can use multiple discards in the same scope. The compiler treats all discards as the same storage location.
  • Are discards variables?

    No, discards are not variables in the traditional sense. They are write-only locations that explicitly indicate you're discarding a value. You cannot read from a discard.
  • Do discards allocate memory?

    Discards are designed to be memory-efficient. The compiler typically doesn't allocate separate memory locations for each discard. All discards in a scope often share the same memory location.
  • What C# version introduced Discards?

    Discards were introduced in C# 7.0.