异步编程:等待一个非异步的函数

时间:2017-09-01 05:38:58

标签: c# asynchronous

首先是问题: 我可以在未标记为 async 的函数中使用 await 吗?

现在的细节。我正在读这篇文章 Hololens- Capturing Photo...正如您所看到的,作者发布了一些代码。 其中包括

 void Start ()
    {
        getFolderPath();
        while (!haveFolderPath)
        {
            Debug.Log("Waiting for folder path...");
        }
        Debug.Log("About to call CreateAsync");
        PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
        Debug.Log("Called CreateAsync");
    }


    async void getFolderPath()
    {
        StorageLibrary myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
        Windows.Storage.StorageFolder savePicturesFolder = myPictures.SaveFolder;
        Debug.Log("savePicturesFolder.Path is " + savePicturesFolder.Path);
        folderPath = savePicturesFolder.Path;
        haveFolderPath = true;
    }

现在注意getFolderPath如何返回void(作为事件处理程序),但是文档说这些方法是无法等待的。作者改为等待使用while循环。

但是,如果我这样做

     void Start ()
        {
            await getFolderPath();

            Debug.Log("About to call CreateAsync");
            PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
            Debug.Log("Called CreateAsync");
        }


     //Notice how now it returns Task
        async Task getFolderPath()
        {
            StorageLibrary myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
//.....
        }

我可以这样做吗? (注意Start()不是Async)

4 个答案:

答案 0 :(得分:3)

人们往往会忘记asyncawait背后的内容。

不,您不能 await的方法不是async,但您可以在返回的ContinueWith上致电Task并提供仅在任务完成时执行的显式继续:

class Example
{
    public void Start()
    {
        getFolderPath()
           .ContinueWith(t =>
           {                   
               Console.WriteLine("...");
           });
    }

    async Task getFolderPath()
    {
        await Task.Delay(1000);
    }
}

这相当于

class Example
{
    public async Task Start()
    {
        await getFolderPath();
        Console.WriteLine("...");
    }


    async Task getFolderPath()
    {
        await Task.Delay(1000);
    }
}

答案 1 :(得分:0)

如果不将方法标记为await,则无法async函数调用。所以你的第二个例子不会编译。但您可以将Start方法标记为async

Async await是一种等待执行函数的非阻塞方法。在这种情况下,执行将在GetFolderPath方法中的await处停止,但是这将等待,Start方法中的执行将继续。我假设,因此,作者使用while loop等待getFolderPath的执行完成。

答案 2 :(得分:0)

第一个问题的答案是不,你不能。来自官方documentation

  

await只能用于async修改的异步方法   关键词。这种方法,使用async修饰符和   通常包含一个或多个await表达式,被称为   异步方法。

如果要在start方法中等待执行异步方法getFolderPath,则需要将签名更新为

public async Task Start ()
{
    await getFolderPath();

    Debug.Log("About to call CreateAsync");
    PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
    Debug.Log("Called CreateAsync");
}

async await上下文中,Task作为返回类型,表示该任务不返回值,该值等同于同步方法中的void。例如,如果您需要从异步任务返回string,则需要public async Task<string> GetFoo()

总的来说,我认为您正在查看的示例中的代码需要进行一些审核。

答案 3 :(得分:0)

您可以明确等待GetFolderPath方法完成:

    void Start ()
    {
        getFolderPath().Wait();

        Debug.Log("About to call CreateAsync");
        PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
        Debug.Log("Called CreateAsync");
    }


 //Notice how now it returns Task
    async Task getFolderPath()
    {
        StorageLibrary myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
        //.....
    }

但是你正在以异步方式转换异步方法,因为Wait是一种阻塞方法(但这就是在while循环中发生的事情)。

如果您的目标是使操作保持异步,则必须遵循DanielOrmeño的建议:

    async Task Start ()
    {
        await getFolderPath();

        Debug.Log("About to call CreateAsync");
        PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
        Debug.Log("Called CreateAsync");
    }