【问题标题】:Create a completed Task<T>创建一个已完成的任务<T>
【发布时间】:2011-05-13 20:34:05
【问题描述】:

我正在实现一个方法Task&lt;Result&gt; StartSomeTask() 并且碰巧在调用该方法之前已经知道结果。如何创建已经完成的Task<T>

这是我目前正在做的事情:

private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var task = new Task<Result>(() => theResult);
    task.RunSynchronously(CurrentThreadTaskScheduler.CurrentThread);
    return task;
}

有没有更好的解决方案?

【问题讨论】:

  • 注意,这个问题的答案也适用于创建一个普通的任务(没有 ),因为 Task 继承自 Task。
  • 请注意,今天有 ValueTask 用于已完成的任务(即对于您已经拥有的值,因此代码基本上是同步的),这将为您节省分配。

标签: c# .net task-parallel-library


【解决方案1】:

你可以试试var myAlreadyCompletedTask = Task.FromResult&lt;string&gt;("MyValue") 这将为您提供具有指定返回类型的任务

【讨论】:

    【解决方案2】:

    不带任何参数调用Task.WhenAll会返回一个完成的任务。

    Task task = Task.WhenAll();
    

    【讨论】:

    • 虽然这可行,但它是一种晦涩难懂的解决方法,可能会在阅读代码时使人们感到困惑,因为它意味着等待不存在的任务
    【解决方案3】:

    当面向 .NET 4.5 时,您可以使用 Task.FromResult:

    public static Task<TResult> FromResult<TResult>(TResult result);
    

    要创建失败的任务,请使用Task.FromException

    public static Task FromException(Exception exception);
    public static Task<TResult> FromException<TResult>(Exception exception);
    

    .NET 4.6 如果您需要非通用的Task,则添加Task.CompletedTask

    public static Task CompletedTask { get; }
    

    旧版本 .NET 的解决方法:

    • 当使用 Async Targetting Pack(或 AsyncCTP)定位 .NET 4.0 时,您可以改用 TaskEx.FromResult

    • 要在 .NET 4.6 之前获得非泛型 Task,您可以使用 Task&lt;T&gt; 派生自 Task 的事实,只需调用 Task.FromResult&lt;object&gt;(null)Task.FromResult(0)

    【讨论】:

    • 要返回一个非通用任务,最好使用Task.FromResult(0)之类的东西。使用“null”作为参数会混淆无法确定泛型参数的编译器。
    • 异常情况如何?异步方法被编译到状态机中,该状态机捕获异常并将它们保存在返回的任务中。即使在第一次等待之前执行的代码也会发生这种情况。返回 Task.FromResult 的方法可能会直接抛出异常。
    • @RobertVažan 一个有趣的边缘案例。可以说,如果您从方法中检索 已知结果,并且该方法抛出异常,则存在需要修复的缺陷。
    • @RobertVažan 您可以轻松编写自己的FromException 方法,其行为类似于FromResult,但代表一个错误任务。如果在结果任务中表示异常很重要,这样的方法可以简单地返回其错误情况。
    • Task.FromException 在 .NET 4.5 中不可用...我认为应该指定它。
    【解决方案4】:

    对于没有返回值的任务,.NET 4.6 增加了Task.CompletedTask

    它返回一个已经在 TaskStatus.RanToCompletion 中的任务。它可能每次都返回相同的实例,但文档警告您不要指望这个事实。

    【讨论】:

      【解决方案5】:

      如果您使用 Rx,另一种方法是 Observable.Return(result).ToTask()。

      【讨论】:

        【解决方案6】:
        private readonly Result theResult = new Result();
        
        public override Task<Result> StartSomeTask()
        {
            var taskSource = new TaskCompletionSource<Result>();
            taskSource.SetResult(theResult);
            return taskSource.Task;
        }
        

        【讨论】:

        • @DanielLobo 如果你解释你的反对意见是什么,你可能会得到答案
        • 不应该是下面那个更简单、赞成票更多的吗? @user2023861
        猜你喜欢
        • 2012-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多