无法将类型'string'隐式转换为'System.Threading.Tasks.Task <string>'

dot*_*ner 60 c# task-parallel-library async-await

我是异步编程的新手,所以在浏览了一些异步样本代码之后,我想到了编写一个简单的异步代码

我创建了一个简单的Winform应用程序,在Form中我编写了以下代码.但它只是不起作用

private Task<string> methodAsync() {
    Thread.Sleep(10000);
    return "Hello"; //Error: Cannot implicitly convert type 'string' to 'System.Threading.Tasks.Task<string>'
}

private async void button1_Click(object sender, EventArgs e)
{
    string s = await methodAsync();
    MessageBox.Show(s);
}
Run Code Online (Sandbox Code Playgroud)

有人可以请点亮一下..

Ser*_*rvy 105

列出的方法返回类型是Task<string>.你正试图回归string.它们不一样,也没有从字符串隐式转换Task<string>,因此错误.

您可能会将此与一种async方法混淆,在该方法中,返回值Task由编译器自动包装在a中.目前该方法不是异步方法.你几乎肯定要这样做:

private async Task<string> methodAsync() 
{
    await Task.Delay(10000);
    return "Hello";
}
Run Code Online (Sandbox Code Playgroud)

有两个关键变化.首先,将该方法标记为async,这意味着将返回类型包装在a中Task,使得该方法进行编译.接下来,我们不想做阻塞等待.作为一般规则,在使用await模型时,请始终避免阻止等待. Task.Delay是一个将在指定的毫秒数后完成的任务.通过await该任务,我们有效地执行了那个时间的非阻塞等待(实际上,该方法的其余部分是该任务的延续).

如果你喜欢4.0的方式,不使用await,你可以这样做:

private Task<string> methodAsync() 
{
    return Task.Delay(10000)
        .ContinueWith(t => "Hello");
}
Run Code Online (Sandbox Code Playgroud)

第一个版本将编译成或多或少像这样的东西,但它将有一些额外的样板代码用于支持错误处理和await我们没有在这里利用的其他功能.

如果你Thread.Sleep(10000)真的只想成为一个长期运行方法的占位符,而不是仅仅等待一段时间,那么你需要确保工作是在另一个线程中完成的,而不是当前的上下文.最简单的方法是Task.Run:

private Task<string> methodAsync() 
{
    return Task.Run(()=>
        {
            SomeLongRunningMethod();
            return "Hello";
        });
}
Run Code Online (Sandbox Code Playgroud)

或者更有可能:

private Task<string> methodAsync() 
{
    return Task.Run(()=>
        {
            return SomeLongRunningMethodThatReturnsAString();
        });
}
Run Code Online (Sandbox Code Playgroud)

  • 如何在“任务”中显式包装“字符串”?还是没有任何方法可以在被调用的方法中不使用`async`和`await`来返回`Task`或`Task &lt;T&gt;`(在这种情况下为methodAsync)? (2认同)
  • 您可以使用 Task.FromResult 将字符串包装在任务中。 (2认同)
  • @dotNETbeginner嗯,如果你不相信我,你可以亲自尝试一下.`await`意味着,启动该任务,一旦它开始,就为该任务添加一个延续,并继续执行异步任务完成后我停止的方法.如果您在异步方法中只使用了"Sleep"然后使用`Task.FromResult`,它将花费整个10秒才启动任务,永远不会返回调用者直到它完成,从而在整个时间内有效地阻止UI线程同步运行整个事物. (2认同)

Jas*_*wal 41

使用FromResult方法

public async Task<string> GetString()
{
   System.Threading.Thread.Sleep(5000);
   return await Task.FromResult("Hello");
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这正是我所需要的,其他答案都没有提供。 (4认同)
  • 据我所知,这是使用Task &lt;T&gt;定义的接口以及同步实现的最佳方法 (2认同)

use*_*853 19

除了有问题的使用async由@Servy指出,另一个问题是,你需要明确地得到TTask<T>调用Task.Result.请注意,Result属性将阻止异步代码,应谨慎使用.

尝试:

private async void button1_Click(object sender, EventArgs e)
{
    var s = await methodAsync();
    MessageBox.Show(s.Result);
}
Run Code Online (Sandbox Code Playgroud)