【问题标题】:Unclear about compiler error when using "out" in async-await block in C#在 C# 的 async-await 块中使用“out”时不清楚编译器错误
【发布时间】:2018-04-26 00:31:06
【问题描述】:

我有一个正在调用的方法,我想确保它在继续之前绝对完成。我也想知道它是否成功完成,所以我正在做以下事情:

async void Foo() {
  bool success;

  // stuff

  await Task.Run(
    () => Bar(out success)
  );

  if (!success) { // this is the line causing the compiler-error
    // handle
  }

  // other stuff
}

void Bar(out bool success);

但我遇到了错误

CS0165 使用未分配的局部变量“成功”

这没什么大不了的,因为我可以变得可爱并初始化success=false 并将其传递为ref 而不是out,这似乎可以按预期工作。但是,我很好奇async-await(或Task.Run)的复杂性似乎会导致无法保证out success 将被正确分配的情况。

感谢任何启发!

编辑:

为了添加更多上下文,以下代码块编译并执行良好。

void Caller() {
  bool success;
  Callee(out success);
  if (success) {
    // do something
  }
}

void Callee();

这是因为out参数在传递之前不需要初始化。更多关于outhttps://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier

【问题讨论】:

  • 导致错误的不是异步,而是您对成功的关闭; Action t = () => { Bar(out success);}; 导致同样的错误
  • @ScubaSteve 这并不是问题所要问的。这更多地是关于为什么如果初始化发生在闭包中,变量仍然被认为是未初始化的。
  • 我认为问题在于 Lambda,而不是异步。 Lambda 在创建变量时“捕获”变量。但是捕获是一种使用形式,你怎么能使用没有初始化的东西呢?尤其是在多任务处理(Lambda 的常见用法)中,捕获变得非常重要。
  • 从编译器的角度来看,不能确定传递给 Task.Run 的委托实际上会在方法返回之前被 Task.Run 调用。是的,我们知道它会,因为我们知道 Task.Run 应该如何工作,并且我们假设它没有任何错误,但是如果 MSFT 错误地实现了它,以至于在一些罕见或奇怪的情况下 Task.Run 实际上并没有运行提供的委托并返回而不抛出任何异常。如果这是可能的(确实如此),那么您的代码可能会在未成功初始化的情况下到达 if 语句。

标签: c# async-await task out


【解决方案1】:

考虑以下Task.Run 的可能(尽管完全不正确)实现:

public class Task
{
    public static Task Run(Action action)
    {
        return Task.Delay(500);
    }
    //...
}

现在想想有问题的代码。通过Task.Run 的这种实现,Bar 方法会被调用吗?不会。因此success 永远不会被初始化,并且会尝试访问未初始化的变量。

编译器不知道Task.Run 的实际实现或它将做什么。它不能假设它没有像我上面那样实现,因此一个未初始化的变量是可能的。

【讨论】:

    猜你喜欢
    • 2019-08-30
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    • 2022-08-24
    • 1970-01-01
    • 2017-05-30
    • 1970-01-01
    • 2021-12-18
    相关资源
    最近更新 更多