【问题标题】:How can I discard both of an argument and a local variable in the same scope?如何在同一范围内同时丢弃参数和局部变量?
【发布时间】:2020-09-15 11:04:37
【问题描述】:

我当前的代码是这样的:

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

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

我知道我可以使用自 C#7.0 以来的丢弃变量 (_),如下所示:

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

或者,

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

但是如果我对它们都使用_,我会遇到错误:

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

错误 CS0029:无法将类型“System.Threading.Tasks.Task”隐式转换为“int”

是否可以丢弃两个未使用的变量?
或者,任何人都可以确认在当前的 C# 规范中这是不可能的吗?


供参考,
如果我省略unusedTask:

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

警告 CS4014:由于未等待此调用,因此在调用完成之前继续执行当前方法。考虑将 'await' 运算符应用于调用结果。

我也想避免这个警告。

【问题讨论】:

  • FooDoAsync 的签名是什么? Foo 是否接受 int 值?
  • 如果你没有从 Foo 返回任务,你应该等待 DoAsync
  • @PavelAnikhouski,我在代码体前面描述了FooDoAsync 的原型作为注释:void Foo(Action&lt;int&gt; action)async Task DoAsync()
  • 您可以使用_ 丢弃返回值。但是 Foo((int intvalue) =&gt; 的 intvalue 不是返回值(这是一个匿名方法)。如果使用_,则为普通参数。
  • 恕我直言,将此问题关闭为“不可重现或由拼写错误引起”是错误分类。该问题清晰且易于重现,并且AFAIK不是由任何无意的错字引起的。只有一个编译错误,问题具体是如何修复这个编译错误,同时保持理想的discard 语法。在我看来,这实际上是一个很好的问题(赞成)。

标签: c# async-await task unused-variables


【解决方案1】:

调用方法时,不能使用discard 代替参数,除非它是out 参数。不过,您可以通过使用双下划线 __ 作为参数来传达相同的语义,以避免与方法主体中使用的任何真正的丢弃发生冲突。

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

【讨论】:

  • 但是使用双下划线或其他参数名称没有区别。这与丢弃无关。参数是一个参数,您可以像string stringvalue = __.ToString(); 一样使用它。 _ 永远不会分配给一个值,你不能使用它。
  • @PinBack 这是真的。 __ 在技术上不是一个丢弃物。它只是一个名称,传达了程序员忽略参数值的意图。看看这个:Using underscore to denote unused parameters in C# lambdas.
【解决方案2】:

您可以使用_ 丢弃返回值。 但是 Foo((intvalue) =&gt; 的 intvalue 不是返回值(这是一个匿名方法)。 如果使用_,则为普通参数。

但您必须小心 _ 在您的示例中丢弃 Task。 举个例子吧:

//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);
}

现在你可以使用这个了:

//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

或者这个:

//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

【讨论】:

  • IntAction(async (intvalue) =&gt; 结果为async void 代表。这很少是一个好主意。
  • @TheodorZoulias 完全正确。这只是为了说明当您使用_Task 作为结果丢弃时会发生什么。
  • 好答案。我误解了参数_ 会被丢弃。如果_只是一个普通参数(它的值可以在方法中使用),它不是真正的丢弃。使用异步方法的潜在错误示例也很好。
猜你喜欢
  • 2013-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-13
  • 2013-12-25
  • 1970-01-01
相关资源
最近更新 更多