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


73

我是异步编程的新手,因此在研究了一些异步示例代码之后,我想到了编写一个简单的异步代码

我创建了一个简单的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);
}

有人可以在这里放点光..

Answers:


124

列出的方法的返回类型为Task<string>。您正在尝试返回string。它们不相同,也没有从string到的隐式转换Task<string>,因此是错误的。

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

private async Task<string> methodAsync() 
{
    await Task.Delay(10000);
    return "Hello";
}

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

如果您更喜欢4.0的方式而不使用await,则可以执行以下操作:

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

第一个版本将编译为大约类似的形式,但是它将在其中包含一些额外的样板代码,以支持错误处理和其他功能。 await我们在这里没有利用的。

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

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

或更可能的是:

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

2
我如何能明确地包裹stringTask?还是没有任何方法可以返回TaskTask<T>不使用asyncawait在被调用的方法中(在这种情况下为methodAsync)?
dotNETbeginner

1
@Aniket不,你错了,有很多方法可以在任务中显式地包装字符串。我会编辑的解决方案。
Servy

@Servy:假设如果我不使用延迟和其他代码,而导致同样的延迟methodAsync,我如何通过将结果字符串包装在Task中来返回结果字符串?
dotNETbeginner

1
您可以使用Task.FromResult将字符串包装在Task中。
Ameen

2
@dotNETbeginner好吧,如果您不相信我,可以自己尝试一下。 await意味着,开始执行该任务,一旦开始,就向该任务添加一个延续,并继续执行异步任务完成后我退出的方法。如果您只是使用过Sleep,然后Task.FromResult在async方法中使用,它将花费整整10秒钟来启动任务,直到完成之前再也不会返回到调用方,这样会一直阻塞UI线程并有效地同步运行整个事情。
2013年

46

使用FromResult方法

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

4
谢谢,这正是我所需要的,没有其他答案。
约翰·亨克尔

3
据我所知,答案是用Task <T>定义的接口实现同步的最佳方法
Simon_Weaver

21

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

尝试:

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

尽管可能不建议这样做,但在某些情况下,我想找回中的Task<string>内容catch {}。我不能await.ToString()产生不正确的结果。这符合要求。
doubleJ 2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.