C# 进度报告

标签 c#

以下代码编译失败:

async Task Foo (Action<int> onProgressPercentChanged)
{
    return Task.Run (() =>
    {
        for (int i = 0; i < 1000; i++)
        {
            if (i % 10 == 0) onProgressPercentChanged (i / 10);

        }
    });
}

由于以下错误:

严重性代码描述项目文件行抑制状态 错误 CS1997 由于“Nutshell.Foo(Action)”是返回“任务”的异步方法,因此返回关键字后不能跟对象表达式。您打算返回“任务”吗?

但这是完全按照书中所示完成的。有什么我想念的吗?

最佳答案

您的方法标记为 async Task ,所以编译器希望它不返回任何东西。如果你想返回一个任务,那么你不应该标记方法 async .或者,您可以使用 awaitasync里面方法。

// Option 1
Task Foo (Action<int> onProgressPercentChanged)
{
  return Task.Run (() =>
  {
    for (int i = 0; i < 1000; i++)
    {
      if (i % 10 == 0) onProgressPercentChanged (i / 10);
    }
  });
}

// Option 2
async Task Foo (Action<int> onProgressPercentChanged)
{
  await Task.Run (() =>
  {
    for (int i = 0; i < 1000; i++)
    {
      if (i % 10 == 0) onProgressPercentChanged (i / 10);
    }
  });
}

有关这两者之间区别的更多信息,请参阅我在 eliding async 上的博客文章.

关于其他问题...

使用 .NET 内置的进度报告,而不是自己滚动。

.NET 使用 IProgress<T>类型,所以你可以使用它:

Task Foo (IProgress<int> progress = null)
{
  return Task.Run (() =>
  {
    for (int i = 0; i < 1000; i++)
    {
      if (progress != null && i % 10 == 0) progress.Report(i / 10);
    }
  });
}

通过遵循进度约定,我们允许调用者请求进度更新,我们还允许使用 Progress<T> 非常自然地编码到 UI 线程:

// Caller, from UI thread
var progress = new Progress<int>(report =>
{
  // Handle progress report. This code is already on the UI thread! :)
});
await Foo(progress);

不要使用 Task.Run在实现中;使用 Task.Run调用方法。 Using Task.Run to implement fake-asynchronous methods is an antipattern .我写了更多关于这个 on my blog

应用此修复程序会使 Foo同步,这是完全正确的,因为它没有实际的异步工作:

void Foo(IProgress<int> progress = null)
{
  for (int i = 0; i < 1000; i++)
  {
    if (progress != null && i % 10 == 0) progress.Report(i / 10);
  }
}

// Caller
var progress = new Progress<int>(report => ...);
await Task.Run(() => Foo(progress));

最后,不要在源头限制进度报告;在接收器处限制它们。如果您的代码曾经在不同的 CPU 上运行,那么您在源代码 (i % 10) 上所做的任何节流都会有问题。最好使用 IProgress<T>节流的实现。

这很好地简化了您的代码:

void Foo(IProgress<int> progress = null)
{
  for (int i = 0; i < 1000; i++)
  {
    if (progress != null) progress.Report(i / 10);
  }
}

关于C# 进度报告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41650207/

相关文章:

c# - 反序列化时的备用属性名称

c# - 为单独的线程使用不同的 .config 文件 (.NET/C#)

c# - 在 MongoDB 中存储动态 JSON 数据

c# - BackgroundWorker ReportProgress 事件队列

c# - 六边形平面的形式和运动表示

c# - 项目引用条件包含多个条件

c# - 如何使用 LINQ 填充类中的集合?

c# - AspNetCore.Identity 不适用于自定义用户/角色实现

c# - 将时差与固定周期进行比较

c# - 如何检查进程名称是否在ListView中?