【问题标题】:Using async await inside void method在 void 方法中使用异步等待
【发布时间】:2023-03-24 02:30:01
【问题描述】:

我有无法更改的签名方法。应该是

protected override void OnInitialize()

使用 Windows 8 Metro API,我需要在这个 NoSignatureChange 方法中检查文件是否存在并读取它。 使用 PlainOldCSharp,我会写类似

protected override void OnInitialize()
{
  ...
  try
  {
    var file = folder.OpenFile(fileName);
    fileExists=true;
  }
  catch(FileNotFoundException)
  {
    fileExists=false
  }
}

记住,在Windows 8 API only way to check if file exists is handling FileNotFoundException 此外,在 Windows 8 API 中,所有 FileIO API 都是异步的,所以我只有 file.OpenFileAsync 方法。

所以,问题是:我应该如何在 Windows 8 API 中使用 folder.OpenFileAsync 方法编写此代码而不更改包含方法的签名

【问题讨论】:

  • 哦,AsTask().Wait() 本身可以抛出 3 个不同的异常
  • 为什么不能更改方法的签名?
  • @svick 我已经更新了问题。
  • 更改签名要好得多。如果您要将某种类库移植到 Metro,那么您猜怎么着?它应该是async(在这种情况下,async Task,而不是async void)。这是最干净的方法。强制 Metro 阻止是可能,但您将在整个过程中与平台和 API 作斗争,而且您肯定会危及您的应用程序被商店批准的机会。
  • 我无法更改第 3 方 SDK。

标签: c# xaml asynchronous windows-8 async-await


【解决方案1】:

您仍然可以使 void 方法异步:

protected async void CannotChangeSignature()
{
    ...
}

异步方法的有效返回类型是:

  • void
  • Task
  • Task<T>

然而,如果你想让它真正阻塞,那么你基本上是在与平台作斗争——重点是避免阻塞。

您说您无法更改签名 - 但如果您依赖此阻塞,那么您必须改变您处理编码的方式。

理想情况下,您应该将签名更改为Task<bool>

protected async Task<bool> CannotChangeSignature()
{
  ...
  try
  {
    await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
    return true;
  }
  catch(FileNotFoundException)
  {
    return false;
  }
}

编辑:如果你真的需要一个阻塞的,你只需要调用AsTask().Wait(),捕获AggregateException并检查它是否包含FileNotFoundException。不过这真的很可怕......你能不能围绕它进行设计,以便它不需要被阻塞?例如,开始检查文件,并在发现文件不存在时显示错误(或其他)。

【讨论】:

  • 话虽如此,除此之外我不会在方法名称中使用“不能”。我不确定这是否违反惯例,但这使得乍一看更难理解正在发生的事情。但我猜这是我的拙见;-)
  • 乔恩,感谢您的回答。是的,我需要阻止它,原因是我在我的应用程序中使用了其他组件,它们定义了接口。
  • Async void 很危险,因为它是非阻塞的,据我所知,你不能让它阻塞。
  • @Erik van Brakel,这是伪代码。方法实际上是protected void OnInitialize(),但与问题无关
  • 您可以使用.GetAwaiter().GetResult() 而不是.AsTask().Wait() 来避免AggregateException
【解决方案2】:
    public async void CalculateData()
    {
        await ProcessData();
    }

    private async Task ProcessData()
    {
        await Task.Run(() =>
        {
            //time taking process
        });
    }

或者你可以使用

public void CalculateData()
{
    ProcessData();
}

private async void ProcessData()
{
    await Task.Run(() =>
    {
        //time taking process
    });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-05
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    相关资源
    最近更新 更多