Konstruktor supports just only one single lifetime concept. To clarify the implications and why I think it covers most use cases, I’ll try to explain what a lifetime scope is:
In Konstruktor, all lifetime scopes together form a tree, a hierarchical structure with one single root.
When an instance needs to be resolved, either by explicitly calling the IScope.resolve() method or by a constructor argument of a dependent object, the scope uses the following resolution algorithm:
Effectively, a newly created instance’s lifetime extends over the scope in which it was first resolved and all its nested branches.
In Konstruktor, there can be only one instance of the same type in one scope.
The implications are:
So it seems to be hard to create transient instances. This is mainly because Konstruktor is focused towards a more service-oriented design, in which transient instance creation is exceptional.
The creation of the transient instances can be made explicit by injecting factories:
Every constructor that refers a Func<> or Func<,> typed argument, gets injected with a factory method that creates a new nested lifetime scope and stores a new instance of the result type in it. So even when an ancestor scope already contains an instance of the same type, a fresh instance is created, potentially hiding a parent one.
All other instances that are requested by dependencies are resolved by the standard rules outlined above.
Until the previous version of Konstruktor, is was not possible to dispose the scopes that were generated by factories.
Now, in the most recent version, scopes and instances that have been created by a factory can now be disposed explicitly. This is solved by requesting Func<Owned<T>> instead of Func<T>.
To access the instance of the return type T, Owned<T>.Value can be used. To dispose the scope and all dependent objects, call Owned<T>.Dispose().
There is a unit test that shows this concept in more detail.
This idea was inspired by Autofac’s Owned<T> mechanism.