-1

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.

ALittleDiff
  • 1,191
  • 1
  • 7
  • 24
  • what is the signatures of `Foo` and `DoAsync`? Is `Foo` accepting an `int` value? – Pavel Anikhouski Sep 15 '20 at 11:09
  • If you are not returning a task from Foo, you should wait DoAsync –  Sep 15 '20 at 11:11
  • @PavelAnikhouski, I described the prototypes of `Foo` and `DoAsync` in front of my code body as a comment: `void Foo(Action action)` and `async Task DoAsync()`. – ALittleDiff Sep 15 '20 at 11:11
  • How would you like to assign a `Task` to an `Action`? – Pavel Anikhouski Sep 15 '20 at 11:13
  • @Aleksandar, this code is just an abstraction(my real code is more complicated). `await DoAsync()` is not an option. – ALittleDiff Sep 15 '20 at 11:14
  • Why `await DoAsync` is not an option?` – Magnus Sep 15 '20 at 11:15
  • @PavelAnikhouski, the code `_ => { DoAsync(); }` is not `Task`, but `Action`. – ALittleDiff Sep 15 '20 at 11:17
  • @Magnus, not every code should `await DoAsync()`. – ALittleDiff Sep 15 '20 at 11:19
  • You mean you can not do it or you do not want to do it? – Magnus Sep 15 '20 at 11:21
  • @Magnus, the functionality of my real code should not await `DoAsync()`. For example: https://stackoverflow.com/questions/42838362/ignoring-the-return-value-from-an-async-task-method – ALittleDiff Sep 15 '20 at 11:23
  • If you don't await it anywhere you will have no idea when or if it finishes or throws any exception. – Magnus Sep 15 '20 at 11:26
  • Take a look at https://stackoverflow.com/help/how-to-ask . It is very hard for us to understand what you problem is. –  Sep 15 '20 at 11:31
  • @Magnus, I could find some example code not awaiting async method: https://www.meziantou.net/fire-and-forget-a-task-in-dotnet.htm . The code looks good for me. – ALittleDiff Sep 15 '20 at 11:34
  • @Aleksandar, do you mean you think the only answer is `await DoAsync()`? My question is simple, usually I discard the unused variable with `_`, but I couldn't in this case. – ALittleDiff Sep 15 '20 at 11:36
  • Is your problem just the warning? If so, you can suppress it in your IDE. If the problem is the actual functionality, please can you clarify what functionality you want? – Tim Sep 15 '20 at 11:41
  • @Tim, yes, there is no problem in functionality. I just want to suppress the warning, but more _graceful_ way. As you mentioned, I can just suppress it with compiler options. It also can be an option. Please give it to me as an 'answer'. – ALittleDiff Sep 15 '20 at 11:43
  • Looks like [this question](https://stackoverflow.com/q/22629951/4051181) is probably your best bet for finding options for how to suppress the error - but to be honest it sounds like you already know how to suppress it, so I must admit I'm still not really sure what you hope to get out of this question. Just pick whichever option you think is most graceful. – Tim Sep 15 '20 at 11:50
  • @Tim, you are right, I already know about using `_`. But the problem is I cannot use `_` in this case. I'm wondering if there exists any _tricky_ way to resolve it. If I cannot avoid this warning with current c# spec, it would also be an answer I expected. If this is the case, I need a confirm from any of c# experts. – ALittleDiff Sep 15 '20 at 11:56
  • I don't know what you mean by graceful and tricky. I've already linked to a question which shows the different ways to suppress it. You are free to use any of the solutions from that question, whichever you like. If you're hoping that someone will tell you which is the most graceful and tricky, then I don't think that's going to happen. It's almost an hour since you asked the question - my honest advice would be to just pick a way of suppressing it from the other question, then move onto other things. Sorry if that's not the answer you wanted, but I genuinely don't know what else to offer you. – Tim Sep 15 '20 at 12:00
  • Let me give you an example: `Foo(async (intvalue) =>` and then use `await DoAsync();` here you wait for execution or `Foo(intvalue =>` and then use `_ = DoAsync();` here you don't wait – PinBack Sep 15 '20 at 12:00
  • @PinBack, `Foo(intvalue => ...)` will work but `intvalue` will never be used. I'd like to discard the unused argument, too. – ALittleDiff Sep 15 '20 at 12:05
  • @Tim, thank you for your link though my question is not a duplicate of it. I cannot take the accepted answer(using `_`) with my case, due to another compiler error. Other answers may work. I may try to pick one of them. – ALittleDiff Sep 15 '20 at 12:21
  • What do you mean with discard argument? Your Foo methode expects an Action-Delegate with int as parameter. You can also write `Foo((int intvalue) =>` – PinBack Sep 15 '20 at 12:25
  • @PinBack, 'argument' means 'parameter', sorry for making you confusing. Though `Foo((int intvalue) =>` will be compiled with no warning/error, it's not perfect for me because `intvalue` remains as an unused parameter. I'm wondering if there is anyway to use `_` for both of `(int unusedValue)` and `var unusedTask = DoAsync()`. – ALittleDiff Sep 15 '20 at 12:36
  • 2
    You can use `_` to discard a return value. But intvalue with `Foo((int intvalue) =>` is not a return value (this is an anonymous method). If you use `_` then it is a normal parameter. – PinBack Sep 15 '20 at 12:54
  • @PinBack, I think your last comment is the right answer. I'd like to accept it as the best answer. Please reopen this question and give me it as an 'answer'. – ALittleDiff Sep 15 '20 at 13:11
  • 2
    IMHO closing this question as "not reproducible or was caused by typos" is a misclassification. The problem is clearly and easily reproducible, and AFAIK it is not caused by any unintentional typo. There is only a compile error, and the question is specifically how to fix this compile error while keeping the desirable [discard](https://learn.microsoft.com/en-us/dotnet/csharp/discards) syntax. It is actually a pretty good question in my opinion (upvoted). – Theodor Zoulias Sep 15 '20 at 13:27

2 Answers2

1

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
PinBack
  • 2,499
  • 12
  • 16
  • The `IntAction(async (intvalue) =>` results to an [`async void`](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void) delegate. This is rarely a good idea. – Theodor Zoulias Sep 15 '20 at 14:54
  • @TheodorZoulias That is absolutely right. It was just to illustrate what happens when you use `_` to discard the `Task` as a Result. – PinBack Sep 15 '20 at 15:06
  • Good answer. I've misunderstood the parameter `_` would be discarded. If `_` is just a normal parameter(it's value can be used in the method), it is not truly-discarded. The example of the potential mistake in using async methods is also nice. – ALittleDiff Sep 15 '20 at 22:39
1

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 an argument, to avoid the clash with any true discards used in the body of the method.

Foo(__ =>
{
    _ = DoAsync();
});
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
  • But it makes no difference if you use double underscore or another parameter name. This has nothing to do with discard. A parameter is a parameter and you can use it like `string stringvalue = __.ToString();`. The `_` is never assigned to a value and you can`t use it. – PinBack Sep 16 '20 at 07:20
  • 1
    @PinBack this is true. The `__` is not technically a discard. It is just a name that communicates the intention of the programmer to ignore the value of the argument. Take a look at this: [Using underscore to denote unused parameters in C# lambdas](https://dismantledtech.wordpress.com/2014/06/07/using-underscore-to-denote-unused-parameters-in-c-lambdas/). – Theodor Zoulias Sep 16 '20 at 10:23