In c# 7.0, you can use discards. What is the difference between using a discard and simply not assigning a variable?
public List<string> DoSomething(List<string> aList)
{
//does something and return the same list
}
_ = DoSomething(myList);
DoSomething(myList);
Is there any difference?
The discard clarifies your intent: the result of the assignment isn't needed or used. The following example uses a standalone discard to ignore the Task object returned by an asynchronous operation. Assigning the task has the effect of suppressing the exception that the operation throws as it is about to complete.
This error is because _ isn't assigned a value, and may not even be assigned a storage location. If it were an actual variable, you couldn't discard more than one value, as the previous example did. Discards are useful in working with tuples when your application code uses some tuple elements but ignores others.
A discard variable used here will not change the fact that it is an unused expression, rather it will appear to the compiler, to you, and others reviewing your code that it was intentionally unused. Thanks for contributing an answer to Stack Overflow!
They enhance its readability and maintainability. You indicate that a variable is a discard by assigning it the underscore ( _) as its name. For example, the following method call returns a tuple in which the first and second values are discards. area is a previously declared variable set to the third component returned by GetCityInformation:
There's absolutely no difference between the two code lines.
Both of them translate to exactly the same IL:
public void A(List<string> myList)
{
_ = DoSomething(myList);
}
public void B(List<string> myList)
{
DoSomething(myList);
}
Both translate to:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: call instance class [System.Private.CoreLib]System.Collections.Generic.List`1<string> C::DoSomething(class [System.Private.CoreLib]System.Collections.Generic.List`1<string>)
IL_0007: pop
IL_0008: ret
You can see it yourself on SharpLab
(Note: I can't actually read IL, but this is the result of both A and B methods)
Discards are useful, as Liam wrote in his answer, for out
parameters you're not going to use, for tuple deconstructions, for pattern matching, and for switch expressions.
You can read all about it in the official documentation.
Update following Liam's comment:
Please note that I'm only referring to this specific scenario.
When used as intended, discards are memory-efficient and/or improve the readability of your code.
Discards are more for out
parameters that you don't care about. For example:
if (int.TryParse(123, out _))
{
....
}
They really only exist to prevent you having to declare a variable that you don't use. So the old way of doing above would be to do:
int throwAway;
if (int.TryParse(123, out throwAway))
{
....
}
To quote the docs:
Because there is only a single discard variable, and that variable may not even be allocated storage, discards can reduce memory allocations. Because they make the intent of your code clear, they enhance its readability and maintainability.
So discards are memory-efficient (though this depends on usage) (don't do this as an optimisation; IMO this very much falls into the area of premature optimisation, as the efficiency gain is tiny) but more importantly they make your code more readable by making it obvious that you don't intend to do anything with the variable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With