【问题标题】:C# Cannot replace void with async TaskC# 无法用异步任务替换 void
【发布时间】:2015-05-14 19:16:29
【问题描述】:

我有以下从实体框架类派生的类如下。

internal class MyInitializer : CreateDatabaseIfNotExists<ConfigurationDbContext>
{
    protected override async void Seed(ConfigurationDbContext context)
    {
        await DbHelper.AddSampleDataAsync(context);
        base.Seed(context);
    }
}

当我将“void”更改为“async Task”时,出现以下编译器错误。

return type must be 'void' to match overridden member

async/await 最佳实践告诉您几乎总是返回 async Task 而不是 void。只是想确保我在这里使用的 void 是使用 void 的可接受场景之一。我还有什么其他选择?

【问题讨论】:

  • 您覆盖了一个方法,因此您必须具有与被覆盖的方法相同的签名。
  • 如果您异步执行工作并且任何调用Seed(通过此类型或通过父类型)的人将在工作实际完成之前返回,该类型是否会正常运行,并且没有提供任何方法来确定此操作的结果(或任何错误)?如果是,则保留 async void 方法,如果不是,则必须要么不异步执行操作,要么不满足此签名。
  • EF 希望这会同步发生,因此您应该同步添加种子数据。
  • @CharlesMager,我认为你是对的。我也认为 EF 应该提供 SeedAsync()。
  • @Servy,由于 EF 不提供 SeedAsync(),JNYRanger 的解决方案看起来还不错,你不觉得吗?

标签: c# async-await


【解决方案1】:

重写方法时,它必须与基类(或接口/抽象类)的原始方法具有相同的签名。我会根据这个问题想象Seed() 的预期行为是同步操作。因此,重写它并将行为完全更改为异步并不是一个好主意。

相反,您应该创建第二个异步方法,并保持同步。

下面的这个方法(如@DanielEarwicker 所建议)允许您通过在Seed()的同步版本中等待异步操作完成来同时拥有同步和异步版本

internal class MyInitializer : CreateDatabaseIfNotExists<ConfigurationDbContext>
{
    protected override void Seed(ConfigurationDbContext context)
    {
        SeedAsync(context).Wait();
    }

    protected async Task SeedAsync(ConfigurationDbContext context)
    {
        await DbHelper.AddSampleDataAsync(context);
        base.Seed(context)
    }
}

【讨论】:

  • 覆盖Seed的重点是对数据库执行初始化任务。改进此答案的一种方法是让Seed 调用SeedAsync 并确保它在从Seed 返回之前已完成。
【解决方案2】:

在 C# 中,被覆盖的成员必须与它们被覆盖的方法具有完全相同的签名。你不能简单地用不同返回类型的另一个方法覆盖一个方法。

由于基类希望方法同步运行,因此您必须等待异步方法完成才能返回。

internal class MyInitializer : CreateDatabaseIfNotExists<ConfigurationDbContext>
{
    protected override void Seed(ConfigurationDbContext context)
    {
        DbHelper.AddSampleDataAsync(context).Wait();
        base.Seed(context);
    }
}

【讨论】:

  • 而且他(至少有可能)无法匹配返回类型并使其正常运行。这是一个悖论。
  • @Servy 他当然可以有if同步功能。这是否“适当”值得商榷。
  • 我们不知道他是否有同步实现,或者是否有,是否适合在此处异步执行此操作。也许是,也许不是。
  • @Servy 您总是可以通过简单地Waiting 异步实现返回的任务来获得同步实现。
  • 不是在某些范例中您不能,例如 winphone/silverlight 应用程序禁用该功能,而在其他范例中,如果您尝试同步执行操作(例如 winform/如果在 UI 线程上同步完成,wpf 应用程序可能会冻结)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多