使用.NET 4.0中的TPL启动新的仅限副作用的任务(即:不返回任何结果的任务)的自动方式是使用以下API:
Task Task.Factory.StartNew(Action<object>, object)
但是为什么这个API的签名看起来不像这个
Task Task.Factory.StartNew<T>(Action<T>, T)
或者像这样
Task Task.Factory.StartNew<T>(T, Action<T>)
技术原因或其他原因?
答案 0 :(得分:7)
好的,现在我正确地理解了这个问题:)
我相信这是因为这是direct replacement for ThreadPool.QueueUserWorkItem
。我同意这看起来有点奇怪...但如果你无论如何都在使用lambda表达式,那么使用做的版本可能更容易采用一个状态参数(即Action
而不是Action<object>
),只是预先捕捉您感兴趣的价值。如果您分别指定值和函数,它将无济于事:(
答案 1 :(得分:3)
根据Stephen Toub(MSFT)的一篇文章,他们假设我们将依赖闭包来传递状态数据。签名含糊不清也有一些借口。 (http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/1988294c-de41-476a-a104-aa550b7409f5)
然而,依靠闭包来解决这个问题似乎是一个暂时的黑客等待更好的解决方案。它有效,但它不是一个好的长期解决方案。很多时候,只需指定一个委托方法,因为动作将是最简单的方法,但这意味着我们必须使用全局变量,否则我们将从状态参数传递中排除。
我喜欢Hugo的一个提议(来自MS论坛发帖)。 Hugo建议引入一个TaskState类型,这似乎是一种避免泛型模糊问题的聪明方法。
将此应用于Task.Factory.StartNew()签名和Task()构造函数:
public Task<T>( Action<T> function, TaskState<T> state );
public Task<T,TResult>( Func<T,TResult> function, TaskState<T> state );
ActionState与Nullable类很相似 - 只是一个围绕Value成员的简单包装器。实际上,使用TaskState可能如下所示:
var myTask = new Task( MyMethod, new TaskState( stateInfo ) );
...
public void MyMethod( StateInfo stateInfo ) { ... }
TaskState&lt;&gt;解决方案并不完美,但它似乎比依靠关闭型铸造更好的解决方案。