【问题标题】:Returning a Task of type Task<Dictionary<string, string>>返回 Task<Dictionary<string, string>> 类型的任务
【发布时间】:2013-06-09 12:59:00
【问题描述】:

我一直在试图弄清楚如何以 Task 类型返回数据,而不是像这样的 int,例如 Task&lt;Dictionary&lt;string, string&gt;&gt;

我似乎找到的所有示例都显示返回Task&lt;int&gt;。说return 42;很容易做到。

我一直在尝试编写的函数是这样的:

Task<Dictionary<string, string>> getDamaged()
{
    Task<Dictionary<string, string>> d = new Task<Dictionary<string, string>>();
    Dictionary<string, string> e = new Dictionary<string, string>();

    foreach (Building i in buildingArray)
    {
        if (Convert.ToInt32(i.efficiency) < 100)
        {
            e.Add(i.buildingID, i.buildingName);
            //d.Add(i.buildingID, i.buildingName);  // this does not work, either
        }
    }

我发现Task.FromResult method 看起来很有希望,但进一步的调查似乎表明TResult 是一项已完成的任务,对我来说听起来不一定像await 那样。

关于如何使其正常工作的任何想法?

更新

这种方法的重点是我试图从我的 UI 线程中卸载工作以保持我的 UI 响应。这是我第一次尝试真正尝试使用带有 .net4.5 的 Visual Studio 2012 来做到这一点。上面的代码是我凭记忆写的。我将发布我一直在尝试的实际代码以及注释掉的失败尝试。

真正困扰我的一个部分是,如果我的返回类型是任务,则如果我返回一个 int,但如果我尝试使用字典,我会收到一个错误,即无法将字典隐式转换为任务

    private Task<Dictionary<string, string>> GetDamagedBuildings()
    {
        //Task<Dictionary<string, string>> damagedBuildings = new Task<Dictionary<string,string>>();
        Dictionary<string, string> d = new Dictionary<string, string>();
        foreach (ButtonPlanetMap i in buttonArray)
        {
            //Dictionary<string, string> d = new Dictionary<string,string>();
            if (Convert.ToInt32(i.efficiency) < 100)
            {
                d.Add(i.buildingID.ToString(), i.buildingName);
                //(Dictionary<string, string>)damagedBuildings.
            }
        }
        //damagedBuildings = Cast d;
        //return damagedBuildings;
        return d;
    }

【问题讨论】:

  • 将函数标记为async
  • 为什么它需要是Task?你的方法是完全同步的,那何必呢?你不能只返回一个Dictionary&lt;string, string&gt;吗?
  • Kirill Shlenskiy 我打算将此方法作为我可以在另一种方法中等待的方法。据我对 async 和 await 的理解,使用关键字 async 你必须在函数的某个地方有一个 await 。并且 await 仅在调用另一个返回任务的方法时才有效。如果我的理解有误,请纠正我。
  • @Jazzeroki:你的问题相当混乱;李和我各自从不同的假设中回答。 Svick 有最好的答案,涵盖了我们的两个答案,而且更清楚。

标签: c# dictionary task async-await


【解决方案1】:

int 没有什么特别之处,您可以通过完全相同的方式从您的方法中返回 Dictionary

你应该做什么取决于你的方法为什么返回Task

  1. 如果您没有充分的理由返回Task,请不要返回Task,直接返回Dictionary
  2. 如果您要返回Task 来实现接口,但您实际上并不想让您的方法异步,Task.FromResult() 是一个很好的解决方案。你可以像这样使用它:return Task.FromResult(dictionary);。这样的Task 仍然可以是awaited,只是await 会立即完成。
  3. 如果您返回 Task,因为您的方法是 CPU 密集型的,并且您想在后台线程上执行它,那么您应该使用 Task.Run()

    return Task.Run(() =>
    {
        var dictionary = new Dictionary<string, string>();
        …
        return dictionary;
    });
    

    但这样做通常不是一个好主意,请参阅Should I expose asynchronous wrappers for synchronous methods?

【讨论】:

  • 我打算让这个方法可以使用异步,因为它是由 ui 调用的,我试图从我的 ui 线程中卸载尽可能多的工作以保持它的响应。
  • 我没有尝试过像您使用 lambda 表达式和匿名方法那样精确地做到这一点。不错的主意,我可以在我正在从事的项目的其他一些领域使用它。真正让我烦恼的是,如果我的返回类型是 task,visual studion 2012 将允许我使用 return 和一个 int,但如果我尝试只返回一个字典,它会给我一个隐式转换错误。这就是为什么我试图弄清楚如何将字典 转换为 Task>
  • @Jazzeroki 您的int 方法是否标记为async?这可以解释差异。此外,MS 对 WinRT 的指导方针是,花费超过 50 毫秒的方法应该是异步的。您的方法是否需要超过 50 毫秒?如果不是,那么它可能不值得async
【解决方案2】:

使用Task.FromResult 将意味着您的方法同步运行,然后返回一个已完成的任务,这可能不是您想要的(尽管您可以等待已完成的任务)。

您可以使用TaskFactory.StartNew 开始新任务。如果您使用的是 .Net 4.5,则可以使用 Task.Run 而不是使用带有一些常见默认参数的 TaskFactory.StartNew

Task<Dictionary<string,string>> GetDamaged()
{
    return Task.Factory.StartNew(() => {
        Dictionary <string, string> e = new Dictionary<string, string>();

        foreach(Building i in buildingArray)
        {
            if(Convert.ToInt32(i.efficiency) < 100)
            {
                e.Add(i.buildingID, i.buildingName);
            }
        }

        return e;
    }
}

【讨论】:

  • Task.Run > Task.Factory.StartNew
  • 我可以谦虚地建议您对答案的呈现方式进行两项改进吗? 1. 它不应包含任何“也不起作用”的内容。作为一个解决方案,所有这些都应该有效。 :) 2. 最好只关注Task.Factory.StartNew(…) 部分,而不是复制并粘贴问题的代码(另请参阅我的第一点);现在,必须将问题的代码与您的答案代码进行比较,以查看使其工作的确切差异。 (当然,这并不难弄清楚。)
【解决方案3】:

当您的async 方法的返回值为Task&lt;int&gt; 时,您的代码应返回int。同样,当您的 async 方法的返回值为 Task&lt;Dictionary&lt;string, string&gt;&gt; 时,您的代码应该返回 Dictionary&lt;string, string&gt;

async Task<Dictionary<string, string>> getDamagedAsync()
{
    Dictionary<string, string> e = new Dictionary<string, string>();

    var buildingArray = await GetBuildingsAsync();
    foreach (Building i in buildingArray)
    {
        if (Convert.ToInt32(i.efficiency) < 100)
        {
            e.Add(i.buildingID, i.buildingName);
        }
    }

    return e;
}

【讨论】:

  • 假设方法是async,我在问题中没有看到任何迹象。
  • 是的。我以为是async,因为操作人员提到他们了解Task&lt;int&gt; 方法如何返回int 值。
  • svick 你是对的,我关闭了 async 关键字。这是故意的,因为我对 async 的理解是,如果没有 await,该方法仍然只是同步运行。斯蒂芬显然,我实际上尝试了您在第一次尝试解决此问题时建议的方法,而 Visual Studio 2012 给我一个错误,说我无法将字典隐式转换为任务
  • @Jazzeroki:async 关键字将 T 转换为 Task&lt;T&gt;
  • Stephen 很明显,谢谢这是我需要的答案。感谢其他所有人的所有其他反馈和提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-21
相关资源
最近更新 更多