【问题标题】:Async method to return true or false in a Task在 Task 中返回 true 或 false 的异步方法
【发布时间】:2015-07-20 09:50:11
【问题描述】:

我知道async 方法只能返回void 或Task。我在async 方法中阅读了类似的异常处理方法。我是 async 编程的新手,所以我正在寻找一个简单的解决方案。

我的async 方法运行一个 Sql 查询。如果查询没问题,它应该用布尔值true 通知调用者,否则通知调用者false。我的方法目前是无效的,所以我无从得知。

private async void RefreshContacts()
{
    Task refresh = Task.Run(() =>
    {
        try
        {
            // run the query
        }
        catch { }
    }
    );
    await refresh;           
}

我只是想将async 更改为Task,以便在我的catch 语句中,该方法将返回false,否则返回true。

【问题讨论】:

    标签: c# asynchronous async-await


    【解决方案1】:

    听起来你只需要返回一个Task<bool> 然后:

    private async Task<bool> RefreshContactsAsync()
    {
        try
        {
            ...
        }
        catch // TODO: Catch more specific exceptions
        {
            return false;
        }
        ...
        return true;
    }
    

    我个人不会捕获异常,而是让调用者检查任务的错误状态,但这是另一回事。

    【讨论】:

    • 当我将返回类型更改为 Task&lt;bool&gt; 后将 catch 更改为 catch { return false; } 时,我收到以下警告消息:“因为不等待此调用,所以在调用之前继续执行当前方法已完成。考虑将 'await' 运算符应用于调用结果。"
    • 检查任务的故障状态听起来更有趣,你能举个简单的例子吗?
    • @Pedram:你从哪里得到这个警告,你有没有尝试过听从它的建议?至于检查任务的故障状态 - 请参阅Task 的文档。虽然如果您等待任务,则会重新抛出异常。
    • 警告出现在我调用方法RefreshContacts()的所有地方如果我在每次调用之前添加等待,这是否意味着我应该将运行此函数的所有函数更改为异步?
    • @Pedram:是的。听起来您从根本上需要退后一步,想想异步刷新联系人意味着什么......
    【解决方案2】:

    将方法签名更改为Task&lt;bool&gt;。然后,如果您的方法被声明为异步,您可以简单地返回一个布尔值。但正如 jon skeet 所说,还有其他可能更好的方法来处理你的情景

     private async Task<bool> RefreshContacts()
        {
            Task refresh = Task.Run(() =>
            {
                try
                {
                    // run the query
                          return true;
            }
            catch { return false;}      
    }
    

    PS:您可能遇到的另一个常见问题是如果您有一个没有异步的方法。然后你可以像这样返回Task.FromResult(true):

     private Task<bool> RefreshContacts()
     {
         ....
        return Task.FromResult(true)
     }
    

    【讨论】:

    • 当我将返回类型更改为Task&lt;bool&gt; 后将捕获更改为catch { return false; } 时,我收到此警告消息:“因为不等待此调用,所以在调用之前继续执行当前方法已完成。考虑将 'await' 运算符应用于调用结果。"
    • 这条消息与catch语句无关。很可能,您在 try 部分中没有任何异步调用。在这种情况下,使用 async 或 Tasks 是没有意义的。
    • 第一个 RefreshContacts 版本无法编译。你能解决它吗?
    【解决方案3】:

    对不起,我认为你们在这里误导了人们。 请参阅 Microsoft 文章 here。

    非常简单的示例,展示了我们如何从任务返回bool、int 或string 类型的(标量)值。

    我在这里发布 C# 代码,以供后人参考:

    using System;
    using System.Linq;
    using System.Threading.Tasks;
    
    public class Example
    {
       public static void Main()
       {
          Console.WriteLine(ShowTodaysInfo().Result);
       }
    
       private static async Task<string> ShowTodaysInfo()
       {
          string ret = $"Today is {DateTime.Today:D}\n" +
                       "Today's hours of leisure: " +
                       $"{await GetLeisureHours()}";
          return ret;
       }
    
       static async Task<int> GetLeisureHours()  
       {  
           // Task.FromResult is a placeholder for actual work that returns a string.  
           var today = await Task.FromResult<string>(DateTime.Now.DayOfWeek.ToString());  
    
           // The method then can process the result in some way.  
           int leisureHours;  
           if (today.First() == 'S')  
               leisureHours = 16;  
           else  
               leisureHours = 5;  
    
           return leisureHours;  
       }  
    }
    // The example displays output like the following:
    //       Today is Wednesday, May 24, 2017
    //       Today's hours of leisure: 5
    // </Snippet >
    

    【讨论】:

      【解决方案4】:

      您似乎正在尝试为同步方法公开异步包装器。不建议这样做,你可以在这里阅读原因:Should I expose asynchronous wrappers for synchronous methods?

      如果你仍然坚持这样做,可以这样做:

      private Task<bool> RefreshContactsAsync()
      {
          return Task.Run(() =>
          {
              try
              {
                  // Run the query
                  return true;
              }
              catch
              {
                  return false;
              }
          });
      }
      

      请注意缺少 async 和 await 关键字。我们只使用Task.Run 重载,它接受Func&lt;TResult&gt; 参数,并返回Task&lt;TResult&gt;。在这种情况下,TResult 的类型为 bool。

      你应该怎么做?只需让您的 RefreshContacts 方法同步即可:

      private bool RefreshContacts()
      {
          try
          {
              // Run the query
              return true;
          }
          catch
          {
              return false;
          }
      }
      

      ...并在调用站点将其包装在 Task.Run 中:

      bool success = await Task.Run(() => RefreshContacts());
      

      这样,没有人会产生错误的印象,即他们正在调用真正的异步方法(doesn't run on a thread 的方法)。意图很明确:同步方法被卸载到ThreadPool,很可能是为了保持 UI 响应。

      【讨论】:

        【解决方案5】:

        谷歌把我带到这里是为了解决一个不同的问题,所以我会回答我正在寻找的东西,希望它可以帮助其他人。

        在第一个示例中,缺少 async 关键字会导致编译器错误

                protected override Task<bool> ShouldMakeADecision()
                {
                    return true;
                }
        

        这将失败,因为您需要编写 async 关键字,如下所示。你可以看到我把它放在保护之后和覆盖之前。

                protected async override Task<bool> ShouldMakeADecision()
                {
                    return true;
                }
        

        【讨论】:

          猜你喜欢
          • 2018-10-26
          • 1970-01-01
          • 2012-02-21
          • 1970-01-01
          • 1970-01-01
          • 2017-09-16
          • 2021-05-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多