Home > other >  How to make sure a task is done before returning from a function?
How to make sure a task is done before returning from a function?

Time:12-21

I have a decent understanding of how Async/Await works in C#.

I understand that when the await keyword is reached, control is given back to the calling function and that is how asynchronous execution is achieved (if I am wrong here, I would appreciate correction and a better explanation).

However I am not sure as to how I would make sure that an async function has finished executing before returning from a function.

Take the example below:

private static async Task<bool> LoadDataIntoLocalAppFile(ZipArchiveEntry entry, string key)
{
    try
    {
        /* SqLiteAsyncConnection is an instance variable in the class that has this function.*/
        string pathToUse = "localDatabase.db"
        if (SqLiteAsyncConnection != null)
        {
            await SqLiteAsyncConnection.CloseAsync()
                .ContinueWith(x => entry.ExtractToFile(pathToUse, true));
        }
        else
        {
            entry.ExtractToFile(pathToUse, true);
        }
        return true;
    }
    catch (Exception ex)
    {
        Colsole.WriteLine(ex.ToString());
        return false;
    }
}

In the above code snippet, I want to make sure that my SqLiteAsyncConnection is closed before I replace the data in the .db file with the contents of entry (so that it does not error out). As such I have used ContinueWith (if this is wrong I would appreciate some clarification).

But I also want to ensure that await SqLiteAsyncConnection.CloseAsync().ContinueWith(x => entry.ExtractToFile(pathToUse, true)); finishes its execution before the function returns. That is I want to ensure that this function does not return true inaccurately, and that it does not return true before await SqLiteAsyncConnection.CloseAsync() .ContinueWith(x => entry.ExtractToFile(pathToUse, true)); finishes its execution.

How do I achieve this?

CodePudding user response:

You don't need the ContinueWith when you have await there. You would use ContinueWith if you don't use await, it can be seen as a type of callback once the parent task has completed/failed.

await SqLiteAsyncConnection.CloseAsync()
                .ContinueWith(x => entry.ExtractToFile(pathToUse, true));

//can be replaced by

await SqLiteAsyncConnection.CloseAsync();
entry.ExtractToFile(pathToUse, true);

When you hit an await section in your code, your function isn't done, it doesn't return true, it gets suspended in a sense and the control is given back to calling thread. Once all your awaits have completed in the function, only then does it return the result.

CodePudding user response:

Your understanding of async/await is incorrect, just awaiting the asynchronous call is enough:

private static async Task<bool> LoadDataIntoLocalAppFile(ZipArchiveEntry entry, string key)
{
    try
    {
        string pathToUse = "localDatabase.db"
        
        await SqLiteAsyncConnection?.CloseAsync();
        entry.ExtractToFile(pathToUse, true);
        
        return true;
    }
    catch (Exception ex)
    {
        Colsole.WriteLine(ex.ToString());
        return false;
    }
}

Then call with:

await LoadDataIntoLocalAppFile(...

CodePudding user response:

When the await keyword is reached, control is given back to the calling function.

I find this commonly used explanation confusing. In simpler terms, the job of an asynchronous method is to create a Task. That's why you call the method, to get a Task back. You get this Task when the first¹ await is reached inside this method. At this point the asynchronous operation has started, and (generally) it has not completed yet. The caller has received the Task that represents the asynchronous operation, and can continue doing other things while the operation is in-flight. In some cases the caller has nothing better to do than wait for the completion of the asynchronous operation, in which case you see this pattern:

await LoadDataIntoLocalAppFile();

Here the caller is itself an asynchronous method. We know it because of the await keyword. The code above is equivalent with this:

Task task = LoadDataIntoLocalAppFile();
await task;

The first line will complete when the first await inside the LoadDataIntoLocalAppFile is reached. The second line will complete when the last line of code inside the LoadDataIntoLocalAppFile has ran.

¹ To be more precise, the first await of a non-completed awaitable.

  • Related