【问题标题】:Cannot implicitly convert type 'string' to 'System.Threading.Tasks.Task<string>'无法将类型“string”隐式转换为“System.Threading.Tasks.Task<string>”
【发布时间】:2013-01-17 10:56:53
【问题描述】:

我是异步编程的新手,所以在看了一些异步示例代码之后,我想到了写一个简单的异步代码

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

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);
}

有人可以在这里放点灯吗..

【问题讨论】:

    标签: c# task-parallel-library async-await


    【解决方案1】:

    列出的方法返回类型是Task&lt;string&gt;。您正在尝试返回 string。它们不一样,也没有从字符串到Task&lt;string&gt;的隐式转换,因此出现错误。

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

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

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

    如果您更喜欢 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();
            });
    }
    

    【讨论】:

    • 我怎样才能将string 明确地包装在Task 中?或者在被调用的方法中不使用asyncawait(在这种情况下为methodAsync)有没有办法返回TaskTask&lt;T&gt;
    • @Aniket 不,你错了,有很多方法可以在任务中显式包装字符串。我将在其中编辑解决方案。
    • @Servy:假设我没有使用延迟和其他代码,这导致methodAsync 中的延迟相同,我应该如何通过将结果字符串包装在任务中来返回结果字符串?
    • 您可以使用 Task.FromResult 将字符串包装在 Task 中。
    • @dotNETbeginner 好吧,如果您不相信我,您可以自己尝试一下。 await 的意思是,启动该任务,一旦启动,就为该任务添加一个延续,并在异步任务完成后继续使用我停止的方法。如果你只是在异步方法中使用Sleep 然后Task.FromResult 它将花费整个 10 秒来启动任务,在它完成之前永远不会返回给调用者,从而一直阻塞 UI 线程并有效地运行整个事情同步进行。
    【解决方案2】:

    使用 FromResult 方法

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

    【讨论】:

    • 谢谢,这正是我所需要的,没有提供其他答案。
    • 据我所知,这个答案是实现使用同步实现的 Task 定义的接口的最佳方法
    【解决方案3】:

    除了@Servy 指出的async 的问题使用之外,另一个问题是您需要通过调用Task.Result 从Task&lt;T&gt; 显式获取T。请注意,Result 属性将阻止异步代码,应谨慎使用。

    试试:

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

    【讨论】:

    • 虽然这可能不被强烈推荐,但有一个实例我想在catch {} 中取回Task&lt;string&gt; 内容。我不能await.ToString() 产生不正确的结果。这符合要求。
    【解决方案4】:
        //source    
        public async Task<string> methodName()
                {
                 return Data;
                 }
    
        //Consumption
         methodName().Result;
    

    希望这会有所帮助:)

    【讨论】:

      【解决方案5】:

      就我而言。

              string ip = _GetStoreIpaddress().Result;
      
      
          private async Task<string> _GetStoreIpaddress()
          {
              string _store_iP = "";
              var Ip_address = await App.SQLiteDb.GetItemsAsync();
              if (Ip_address != null)
              {
                  _store_iP = Ip_address.ToString();
              }
      
              return _store_iP;
          }
      

      【讨论】:

      • 首先,这并不能回答所提出的问题。其次,这段代码确实有很多问题。非常奇怪的符号,在这个微小的方法中甚至不一致。将 Result() 调用显示为解决方案的一部分是另一个大问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-27
      • 1970-01-01
      相关资源
      最近更新 更多