By default, tasks are started automatically when they are injected. It is recommended to use an argument of type CancellationToken to the composition root to be able to cancel the execution of a task. In this case, the composition root property is automatically converted to a method with a parameter of type CancellationToken. To start a task, an instance of type TaskFactory is used, with default settings:
- CancellationToken.None
- TaskScheduler.Default
- TaskCreationOptions.None
- TaskContinuationOptions.None
But you can always override them, as in the example below for TaskScheduler.Current.
interface IDependency
{
ValueTask DoSomething(CancellationToken cancellationToken);
}
class Dependency : IDependency
{
public ValueTask DoSomething(CancellationToken cancellationToken) => ValueTask.CompletedTask;
}
interface IService
{
Task RunAsync(CancellationToken cancellationToken);
}
class Service(Task<IDependency> dependencyTask) : IService
{
public async Task RunAsync(CancellationToken cancellationToken)
{
var dependency = await dependencyTask;
await dependency.DoSomething(cancellationToken);
}
}
DI.Setup(nameof(Composition))
.Hint(Hint.Resolve, "Off")
// Overrides TaskScheduler.Default if necessary
.Bind<TaskScheduler>().To(_ => TaskScheduler.Current)
// Specifies to use CancellationToken from the composition root argument,
// if not specified then CancellationToken.None will be used
.RootArg<CancellationToken>("cancellationToken")
.Bind<IDependency>().To<Dependency>()
.Bind<IService>().To<Service>()
// Composition root
.Root<IService>("GetRoot");
var composition = new Composition();
using var cancellationTokenSource = new CancellationTokenSource();
// Creates a composition root with the CancellationToken passed to it
var service = composition.GetRoot(cancellationTokenSource.Token);
await service.RunAsync(cancellationTokenSource.Token);
The following partial class will be generated:
partial class Composition
{
private readonly Composition _root;
[OrdinalAttribute(10)]
public Composition()
{
_root = this;
}
internal Composition(Composition parentScope)
{
_root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IService GetRoot(CancellationToken cancellationToken)
{
TaskFactory<IDependency> perBlockTaskFactory3;
CancellationToken localCancellationToken53 = cancellationToken;
TaskCreationOptions transientTaskCreationOptions4 = TaskCreationOptions.None;
TaskCreationOptions localTaskCreationOptions54 = transientTaskCreationOptions4;
TaskContinuationOptions transientTaskContinuationOptions5 = TaskContinuationOptions.None;
TaskContinuationOptions localTaskContinuationOptions55 = transientTaskContinuationOptions5;
TaskScheduler transientTaskScheduler6 = TaskScheduler.Current;
TaskScheduler localTaskScheduler56 = transientTaskScheduler6;
perBlockTaskFactory3 = new TaskFactory<IDependency>(localCancellationToken53, localTaskCreationOptions54, localTaskContinuationOptions55, localTaskScheduler56);
Func<IDependency> perBlockFunc2 = new Func<IDependency>([MethodImpl(MethodImplOptions.AggressiveInlining)] () =>
{
IDependency localValue57 = new Dependency();
return localValue57;
});
Task<IDependency> transientTask1;
// Injects an instance factory
Func<IDependency> localFactory58 = perBlockFunc2;
// Injects a task factory creating and scheduling task objects
TaskFactory<IDependency> localTaskFactory59 = perBlockTaskFactory3;
// Creates and starts a task using the instance factory
transientTask1 = localTaskFactory59.StartNew(localFactory58);
return new Service(transientTask1);
}
}
Class diagram:
---
config:
class:
hideEmptyMembersBox: true
---
classDiagram
Service --|> IService
Dependency --|> IDependency
Composition ..> Service : IService GetRoot(System.Threading.CancellationToken cancellationToken)
Service *-- TaskᐸIDependencyᐳ : TaskᐸIDependencyᐳ
TaskᐸIDependencyᐳ o-- "PerBlock" FuncᐸIDependencyᐳ : FuncᐸIDependencyᐳ
TaskᐸIDependencyᐳ o-- "PerBlock" TaskFactoryᐸIDependencyᐳ : TaskFactoryᐸIDependencyᐳ
FuncᐸIDependencyᐳ *-- Dependency : IDependency
TaskFactoryᐸIDependencyᐳ o-- CancellationToken : Argument "cancellationToken"
TaskFactoryᐸIDependencyᐳ *-- TaskCreationOptions : TaskCreationOptions
TaskFactoryᐸIDependencyᐳ *-- TaskContinuationOptions : TaskContinuationOptions
TaskFactoryᐸIDependencyᐳ *-- TaskScheduler : TaskScheduler
namespace Pure.DI.UsageTests.BCL.TaskScenario {
class Composition {
<<partial>>
+IService GetRoot(System.Threading.CancellationToken cancellationToken)
}
class Dependency {
+Dependency()
}
class IDependency {
<<interface>>
}
class IService {
<<interface>>
}
class Service {
+Service(TaskᐸIDependencyᐳ dependencyTask)
}
}
namespace System {
class FuncᐸIDependencyᐳ {
<<delegate>>
}
}
namespace System.Threading {
class CancellationToken {
<<struct>>
}
}
namespace System.Threading.Tasks {
class TaskContinuationOptions {
<<enum>>
}
class TaskCreationOptions {
<<enum>>
}
class TaskFactoryᐸIDependencyᐳ {
}
class TaskScheduler {
<<abstract>>
}
class TaskᐸIDependencyᐳ {
}
}