Skip to content

Latest commit

 

History

History
170 lines (146 loc) · 5.7 KB

task.md

File metadata and controls

170 lines (146 loc) · 5.7 KB

Task

CSharp

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;
  private readonly object _lock;

  public Composition()
  {
    _root = this;
    _lock = new object();
  }

  internal Composition(Composition parentScope)
  {
    _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root;
    _lock = _root._lock;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public IService GetRoot(CancellationToken cancellationToken)
  {
    var perResolveFunc45 = default(Func<IDependency>);
    TaskScheduler transientTaskScheduler5 = TaskScheduler.Current;
    TaskContinuationOptions transientTaskContinuationOptions4 = TaskContinuationOptions.None;
    TaskCreationOptions transientTaskCreationOptions3 = TaskCreationOptions.None;
    TaskFactory<IDependency> perBlockTaskFactory2;
    {
        CancellationToken localCancellationToken26 = cancellationToken;
        TaskCreationOptions localTaskCreationOptions27 = transientTaskCreationOptions3;
        TaskContinuationOptions localTaskContinuationOptions28 = transientTaskContinuationOptions4;
        TaskScheduler localTaskScheduler29 = transientTaskScheduler5;
        perBlockTaskFactory2 = new TaskFactory<IDependency>(localCancellationToken26, localTaskCreationOptions27, localTaskContinuationOptions28, localTaskScheduler29);
    }

    if (perResolveFunc45 == null)
    {
        lock (_lock)
        {
            if (perResolveFunc45 == null)
            {
                perResolveFunc45 = new Func<IDependency>(
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                () =>
                {
                    IDependency localValue30 = new Dependency();
                    return localValue30;
                });
            }
        }
    }

    Task<IDependency> transientTask1;
    {
        Func<IDependency> localFactory31 = perResolveFunc45!;
        TaskFactory<IDependency> localTaskFactory32 = perBlockTaskFactory2;
        transientTask1 = localTaskFactory32.StartNew(localFactory31);
    }

    return new Service(transientTask1);
  }
}

Class diagram:

classDiagram
	class Composition {
		<<partial>>
		+IService GetRoot(System.Threading.CancellationToken cancellationToken)
	}
	class TaskCreationOptions
	class TaskContinuationOptions
	class TaskFactory
	class TaskScheduler
	class CancellationToken
	Dependency --|> IDependency
	class Dependency {
		+Dependency()
	}
	Service --|> IService
	class Service {
		+Service(TaskᐸIDependencyᐳ dependencyTask)
	}
	class TaskᐸIDependencyᐳ
	class FuncᐸIDependencyᐳ
	class TaskFactoryᐸIDependencyᐳ
	class IDependency {
		<<interface>>
	}
	class IService {
		<<interface>>
	}
	Composition ..> Service : IService GetRoot(System.Threading.CancellationToken cancellationToken)
	TaskFactory o-- CancellationToken : Argument "cancellationToken"
	TaskFactory *--  TaskCreationOptions : TaskCreationOptions
	TaskFactory *--  TaskContinuationOptions : TaskContinuationOptions
	TaskFactory *--  TaskScheduler : TaskScheduler
	Service *--  TaskᐸIDependencyᐳ : TaskᐸIDependencyᐳ
	TaskᐸIDependencyᐳ o-- "PerResolve" 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