ALittleDiff
ALittleDiff

Reputation: 1211

How can I discard both of an argument and a local variable in the same scope?

My current code seems like this:

// for given methods like these:
// void Foo(Action<int> action)
// async Task DoAsync()

Foo(unusedInt =>
{
  var unusedTask = DoAsync();
});

I know I can use the discard variable(_) since C#7.0, like this:

Foo(_ =>
{
  var unusedTask = DoAsync();
});

Or,

Foo(unusedInt =>
{
  _ = DoAsync();
});

But I meet an error if I use _ for both of them:

Foo(_ =>
{
  _ = DoAsync();  // error CS0029
});

error CS0029: Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'int'

Is there anyway to discard both of the unused variables?
Or, can anyone confirm that it would not be possible within the current C# spec?


For reference,
If I omit the unusedTask:

Foo(_ =>
{
  DoAsync();  // warning CS4014
});

warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

I'd like to avoid this warning, either.

Upvotes: -1

Views: 675

Answers (2)

Theodor Zoulias
Theodor Zoulias

Reputation: 43845

When calling a method, a discard cannot be used in place of an argument, unless it is an out argument. Nevertheless you could convey the same semantics by using a double underscore __ as the name of the parameter, to avoid the clash with any true discards used in the body of the method.

Foo(__ =>
{
    _ = DoAsync();
});

The __ is not technically a discard. It is just a parameter name that communicates the intention of the programmer to ignore the value of the argument. Take a look at this article by Chris Mantle: Using underscore to denote unused parameters in C# lambdas.

Upvotes: 3

PinBack
PinBack

Reputation: 2574

You can use _ to discard a return value. But intvalue with Foo((intvalue) => is not a return value (this is an anonymous method). If you use _ then it is a normal parameter.

But you must be careful with _ to discard a Task in your example. Let me give you an example:

//Your async method
public async Task DoAsync()
{
    Console.WriteLine("Start DoAsync");
    await Task.Delay(2000);
    Console.WriteLine("End DoAsync");
}

//a method that expects a Action-Delegate with 1 int as parameter
public void IntAction(Action<int> action)
{
    action(2);
}

Now you can use this:

//Here the DoAsync wait 2 Seconds and then write 2 to Console
IntAction(async (intvalue) =>
{
    await this.DoAsync();
    Console.WriteLine(intvalue.ToString());
});
//Output is:
//Start DoAsync
//End DoAsync
//2

Or this:

//Here the DoAsync will not wait and write 2 to Console (discard Task)
IntAction(intvalue =>
{
    _ = this.DoAsync();
    Console.WriteLine(intvalue.ToString());
});
//Output is:
//Start DoAsync
//2
//End DoAsync

Upvotes: 1

Related Questions