-
Notifications
You must be signed in to change notification settings - Fork 3
Home
Welcome to the DpdtInject wiki!
Dpdt is a DI container based on C# Source Generators. Its goal is to remove everything possible from runtime and make resolving process as faster as we can. This is achieved by transferring huge piece of resolving logic to the compilation stage into the source generator.
It's only a proof-of-concept. Nor alpha, neither beta.
- Easy-to-read syntax
Bind<IA>().To<A>().WithTransientScope()
. - Generic
Get<T>
and non genericGet(Type t)
resolution. - Single object
Get
or collectionGetAll
resolution. - Custom constructor arguments
... Configure(new ConstructorArgument("message", Message))
. - Transient, singleton and constant (in progress) scopes.
- Additional compile-time safety: First Second
- At last, it's very, very fast.
More to come!
Because of source generators are generating new code based on your code, it's impossible to direclty debug your Module code, including its When
predicates (because this code is not actually executed at runtime). It's a disadvantage of Dpdt design. For conditional clauses, you need to call another class to obtain an ability to catch a breakpoint:
public partial class MyModule : DpdtModule
{
public override void Load()
{
Bind<IA, IA2>()
.To<A>()
.WithSingletonScope()
.When(cc =>
{
//here debugger is NOT working
return Debugger.Debug(cc);
})
;
}
}
public static class Debugger
{
public static bool Debug(IResolutionContext rc)
{
//here debugger is working
return true;
}
}
Examples of allowed syntaxes are available in the test project. Please refer that code.
Constructor is chosen at the compilation stage based on 2 principles:
- Constructors are filtered by
ConstructorArgument
filter. If noConstructorArgument
has defined, all existing constructors will be taken. - The constructor with the minimum number of parameters is selected to make binding.
Also, Dpdt will break ongoing compilation if binding has useless ConstructorArgument
clause (no constructor with this parameter exists).
Bind clause with no defined scope raises a question: an author did forgot set a scope or wanted a default scope? We make a decision not to have a default scope and force a user to define a binding.
The only one instance of defined type is created. If instance is IDisposable
then Dispose
method will be invoked at the moment the kernel are disposing.
Each resolution call results with new instance. Dispose
for targets will not be invoked.
(in progress)
Constant scope is a scope when the kernel receive an outside-created object. Its Dispose
will not be invoked, because the kernel was not a parent of the constant object.
Each bind clause may have an additional filter e.g.
Bind<IA>()
.To<A>()
.WithSingletonScope()
.When(IResolutionContext rc =>
{
condition to resolve
})
;
Please refer unit tests to see the examples. Please note, than any filter makes a resolution process slower (a much slower! 10x slower in compare of unconditional binding!), so use this feature responsibly.
Dpdt can detect cases of singleton takes a transient as its dependency, and make signals to the programmer. Please refer to the tests for additional information.