可以从TPL任务派生从方法返回更多细节吗?

Mik*_*liy 13 .net c# asynchronous task-parallel-library async-ctp

我的原始方法如下:

string DoSomeWork();
Run Code Online (Sandbox Code Playgroud)

方法DoSomeWork在其他线程上启动一些工作并返回执行ID(只是随机字符串).稍后我可以通过给定的执行ID查询结果.重点是在作业完成之前使执行ID可用.

现在我想更改签名以返回Task,因此用户可以等待.

Task DoSomeWork();
Run Code Online (Sandbox Code Playgroud)

同时我仍然需要返回执行ID(例如用于跟踪),我看到几个选项.首先是if out参数,第二个是返回带有执行ID和任务的元组(在C#中看起来不是最好的选项),第三个是我真正想要问的.

如果我将创建将从Task类派生的类,该怎么办:

public class ExtendedTask : Task
{
     public string ExecutionID {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

这看起来不错吗?或者最好决定其他选择?

PS在BCL中有一些派生自Task类.

更新,似乎我无法定义这个明确的enouthg.但是我需要在作业完成之前访问ExecutionID,因此我无法使用Task.Result.

Jon*_*eet 13

我个人不会延伸 Task<T>,我会改编.这样您就不必担心任何只返回的API Task<T>- 您可以将任务包装起来.你可以拥有一个暴露底层任务的属性,而对于C#5异步目的,你可以在你自己的类型上实现awaiter模式 - 但是我觉得创建你自己的派生类型可能弊大于利.尽管如此,这主要是一种直觉.

另一种选择是反过来:将你的额外状态存储在Task.AsyncState财产中; 毕竟,这就是它的用途.这样,您可以轻松地传递任务,而不会丢失它在逻辑上属于的执行上下文.


Ree*_*sey 11

我建议使用Task<T>,因为它允许您"嵌入"任务结果中的其他信息.

例如,在您的情况下,有类似的东西可能是有意义的:

class ExecutionResult
{
     public int ExecutionID { get; set; }
     public string Result { get; set; }
     // ...
}


public Task<ExecutionResult> DoSomeWork()
{
     return Task.Factory.StartNew( () =>
     {
          // Replace with real work, etc...
          return new ExecutionResult { ExecutionID = 0, Result = "Foo" };
     });
}
Run Code Online (Sandbox Code Playgroud)

编辑以回应评论:

如果您需要"之前"任务完成的数据,并且为了其他目的而尝试访问它,我建议创建一个包含Task和其他数据的类,并返回它,即:

class ExecutionResult
{
     public int ExecutionID { get; private set; }
     public Task<string> Result { get; private set; }
     // ... Add constructor, etc...
}


public ExecutionResult DoSomeWork()
{
     var task = Task.Factory.StartNew( () =>
     {
          // Replace with real work, etc...
          return "Foo";
     });

     return new ExecutionResult(1, task); // Make the result from the int + Task<string>
}
Run Code Online (Sandbox Code Playgroud)

这仍然可以让您访问有关您的流程和Task/的信息Task<T>.