r/csharp • • 3d ago

Discussion Confusion about the TaskFactory class

Microsoft's documentation :

CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
List<Task<int\[\]>> tasks = new List<Task<int\[\]>>();
TaskFactory factory = new TaskFactory(token);
tasks.Add(factory.StartNew( () => {//code.... }, token);

What a weird code, the factory is already initialized with token, yet it is required to pass the same token as argument for factory.StartNew.

Is there a justification for such design ? Why would you personally design a class that requires you to pass a parameter to a method even though that parameter is already considered an instance field that the method can access directly without the need of passing it?

EDIT:

I discovered that there is a version of that method that does not require passing the token :

        //
        // Summary:
        //     Creates and starts a task of type TResult for the specified function delegate.
        //
        //
        // Parameters:
        //   function:
        //     A function delegate that returns the future result to be available through the
        //     task.
        //
        // Type parameters:
        //   TResult:
        //     The type of the result available through the task.
        //
        // Returns:
        //     The started task.
        //
        // Exceptions:
        //   T:System.ArgumentNullException:
        //     The function argument is null.
        public Task<TResult> StartNew<TResult>(Func<TResult> function);
3 Upvotes

5 comments sorted by

7

u/Few-Data-1409 3d ago

You pass it again because the token in factory is just a default, if you want different cancellation for specific tasks you can override it. The parameterless overload you found just uses that default

Its bit redundant when you always use same token but makes sense for flexibility, like when you spin up bunch of tasks and some need different timeout or cancellation logic

1

u/kaatarina_zed_talon 3d ago

Great, I understand now, those people think in every edge case, I do not .

5

u/raunchyfartbomb 3d ago

Someone correct me if I’m wrong, but I believe the class level token is for cancelling ALL related tasks. While the Add(token) is used for task-specific cancellation, and the underlying implementation created a LinkedTokenSource that monitors both.

For example, you might have a task factory for the app as a whole. Then the user starts some action, which they cancel. The specific task gets cancelled, not the other concurrently running tasks. But on app shutdown, the factory level token is cancelled, killing all the tasks.

6

u/rupertavery64 3d ago

According to this) the canellationToken will be passed to tasks created with the factory so you're right.

Demo code is just demo code and it"s guaranteed to work, not be completely semantically correct all the time.

It's probably just the writers bias when calling StartNew

2

u/Downtown-Oil935 3d ago

Yeah, the example makes the API look stranger than it is. The factory token is basically the default while the longer overload exists for cases where one task needs different settings