如何从异步任务中返回结果?

39

我想从异步任务中返回一个字符串结果。

System.Threading.Tasks.Task.Run(async () => await audatex.UploadInvoice(assessment, fileName));

public async Task UploadInvoice(string assessment, string fileName)
{
    //Do stuff
    return string;
}

异步编程让我感到困惑,有人能解释一下吗?


1
你尝试了什么/问题出在哪里?快速谷歌搜索得到了如何:从一个任务中返回值。你需要将Task改为Task<string> - Charles Mager
4个回答

54

异步编程可能需要一些时间来理解,所以我会发布对我有用的内容,以便帮助其他人。

如果你想将业务逻辑与异步代码分开,则可以使你的UploadInvoice方法不包含异步:

private string UploadInvoice(string assessment, string filename)
{
    // Do stuff    
    Thread.Sleep(5000);

    return "55";
}

然后,您可以创建一个异步包装器:

private async Task<string> UploadInvoiceAsync(string assessment, string filename)
{
    return await Task.Run(() => UploadInvoice(assessment, filename));
}

给你选择称呼的权利:

public async Task CallFromAsync()
{
    string blockingInvoiceId = UploadInvoice("assessment1", "filename");
    
    string asyncInvoiceId = await UploadInvoiceAsync("assessment1", "filename");
}
有时候,您可能需要从非异步方法调用异步方法。
// Call the async method from a non-async method
public void CallFromNonAsync()
{
    string blockingInvoiceId = UploadInvoice("assessment1", "filename");
                
    Task<string> task = UploadInvoiceAsync("assessment1", "filename");
        string invoiceIdAsync = task.GetAwaiter().GetResult();
}

----编辑:由于人们发现这很有用,所以添加更多示例----

有时您想等待任务完成,或在完成后使用一个方法继续任务。以下是您可以在控制台应用程序中运行的工作示例。

class Program
{
    static void Main(string[] args)
    {
        var program = new Program();
        program.Run();
        Console.ReadKey();
    }
    
    async void Run()
    {
        // Example 1
        Console.WriteLine("#1: Upload invoice synchronously");
        var receipt = UploadInvoice("1");
        Console.WriteLine("Upload #1 Completed!");
        Console.WriteLine();
    
        // Example 2
        Console.WriteLine("#2: Upload invoice asynchronously, do stuff while you wait");
        var upload = UploadInvoiceAsync("2");
        while (!upload.IsCompleted)
        {
            // Do stuff while you wait
            Console.WriteLine("...waiting");
            Thread.Sleep(900);
        }
        Console.WriteLine("Upload #2 Completed!");
        Console.WriteLine();
    
        // Example 3
        Console.WriteLine("#3: Wait on async upload");
        await UploadInvoiceAsync("3");
        Console.WriteLine("Upload #3 Completed!");
        Console.WriteLine();
    
        // Example 4
        var upload4 = UploadInvoiceAsync("4").ContinueWith<string>(AfterUploadInvoice);
    }
    
    string AfterUploadInvoice(Task<string> input)
    {
            Console.WriteLine(string.Format("Invoice receipt {0} handled.", input.Result));
        return input.Result;
    }
    
    string UploadInvoice(string id)
    {
        Console.WriteLine(string.Format("Uploading invoice {0}...", id));
        Thread.Sleep(2000);
        Console.WriteLine(string.Format("Invoice {0} Uploaded!", id));
        return string.Format("<{0}:RECEIPT>", id); ;
    }

    Task<string> UploadInvoiceAsync(string id)
    {
        return Task.Run(() => UploadInvoice(id));
    }
}

3
CallFromNonAsync() 可能会死锁,这取决于当前线程是否为线程池线程。 - Joshua
在我看来,@Joshua,这似乎超出了问题的范围。这是非常基本的异步代码。但是,在这种情况下,CallFromNonAsync应该从主UI线程或线程池线程(例如Task.Run(() => CallFromNonAsync()))中运行。 - stuzor
2
如果您正在线程池线程上运行,请勿阻塞等待线程池线程完成。这就是死锁发生的原因。 - Joshua

32
你的方法应该返回 Task<string>,而不是 Task
public async Task<string> UploadInvoice(string assessment, string fileName)
{
    //Do stuff
    return "some string";
}

1
我该如何调用它? - Pomster
@Pomster,如我所提到的:string result = await UploadInvoice("", "") - Ric
7
await运算符需要在async和返回类型为Task的函数中使用。如果我添加Task.Run(async () => wait UploadInvoice...),我会得到错误信息..."无法隐式将类型'System.Threading.Tasks.Task<string>'转换为'string'". - Pomster

7
public async Task<string> UploadInvoice(string assessment, string fileName)
{
    string result = GetResultString();//Do stuff    
    return Task.FromResult(result);
}

4
尽管这段代码可能是解决方案,但是包括解释真的有助于提高您发布的质量。请记住,您正在回答未来读者的问题,而那些人可能不知道您提出代码建议的原因。 - Adam

4

请执行以下步骤:

public async Task<string> UploadInvoice(string assessment, string fileName)

然后等待结果:

string result = await UploadInvoice("", "");

更多示例可以在这里查看:

异步返回类型


1
我遇到了这个错误。'await' 操作符只能在异步方法中使用。请考虑使用 'async' 修饰符标记此方法,并将其返回类型更改为 'Task'。 - Pomster
你需要在一个async方法中调用它,我猜你没有这样做?尝试以下代码:var myTask = Task.Run(() => a.UploadInvoice("", "")); string result = myTask.Result; - Ric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接