The idomatic way to start a new side-effect-only task (that is: a task that returns no result) using the TPL in .NET 4.0 is using the following API:
Task Task.Factory.StartNew(Action<object>, object)
But why doesn't the signature of this API look like this
Task Task.Factory.StartNew<T>(Action<T>, T)
or like this
Task Task.Factory.StartNew<T>(T, Action<T>)
Technical reasons or some other reason?
Okay, now that I understand the question properly :)
I believe it's because this is meant to be a direct replacement for ThreadPool.QueueUserWorkItem
. I do agree that it seems somewhat odd... but if you're using lambda expressions anyway, it's probably easier to use the version that does take a state parameter (i.e. Action
instead of Action<object>
) and just capture the value you're interested in beforehand. It doesn't help if you're specifying the value and the function separately :(
According to a post by Stephen Toub (MSFT), they are assuming that we are going to rely on closures to pass state data. There was also some excuse about signature ambiguity. (http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/1988294c-de41-476a-a104-aa550b7409f5)
However, relying on closures to solve this problem seems like a temporary hack waiting for a better solution. It works, but it's not a good longer-term solution. There are many times that simply specifying a delegate method as the action would be the simplest approach, but that means we have to use global vars or we're excluded from state parameter passing.
I like one of Hugo's proposals (from the MS forum posting). Hugo suggested introducing a TaskState type, which seems like a clever way to circumvent the generics ambiguity issue.
Applying this to the Task.Factory.StartNew() signature and the Task() constructor as such:
public Task<T>( Action<T> function, TaskState<T> state );
public Task<T,TResult>( Func<T,TResult> function, TaskState<T> state );
ActionState would be a lot like the Nullable class -- just a simple wrapper around a Value member. In practice, using TaskState might look like this:
var myTask = new Task( MyMethod, new TaskState( stateInfo ) );
...
public void MyMethod( StateInfo stateInfo ) { ... }
The TaskState<> solution is not perfect, but it seems like a much better solution than relying on closure of type casting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With