Add ability to register a type while resolving it

Closes #5
This commit is contained in:
Mike Bierlee 2016-02-03 22:55:18 +01:00
parent 7775dd3c3a
commit 9ebbb5d917
4 changed files with 336 additions and 299 deletions

View file

@ -3,6 +3,8 @@ Poodinis Changelog
**Version NEXT** **Version NEXT**
* ADD setting persistent registration options * ADD setting persistent registration options
* DEPRECATE DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION, use doNotAddConcreteTypeRegistration instead * DEPRECATE DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION, use doNotAddConcreteTypeRegistration instead
* ADD resolve options to container resolve()
* ADD ability to register a type while resolving it. Use resolve option registerBeforeResolving
**Version 6.0.0** **Version 6.0.0**
* CHANGE registration scopes are replaced by a single factory implementation. If you were not doing anything with the internal scope mechanism, you * CHANGE registration scopes are replaced by a single factory implementation. If you were not doing anything with the internal scope mechanism, you

View file

@ -40,6 +40,11 @@ dependencies.register!(ExampleInterface, ExampleClass)(RegistrationOptions.DO_NO
auto exampleClassInstance = dependencies.resolve!ExampleInterface; auto exampleClassInstance = dependencies.resolve!ExampleInterface;
auto exampleClassInstance2 = dependencies.resolve!ExampleClass; // A ResolveException is thrown auto exampleClassInstance2 = dependencies.resolve!ExampleClass; // A ResolveException is thrown
``` ```
It is also possible to register a type while resolving it. Doing so means you don't need to explicitly register it beforehand. To do this, use the resolve option "registerBeforeResolving":
```d
dependencies.resolve!ExampleClass([ResolveOption.registerBeforeResolving]);
```
Naturally this can only be done when you are resolving a concrete type or an interface type by qualifier.
Dependency creation behaviour Dependency creation behaviour
----------------- -----------------

View file

@ -61,6 +61,18 @@ public enum RegistrationOption {
DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION
} }
/**
* Options which influence the process of resolving dependencies
*/
public enum ResolveOption {
/**
* Registers the type you're trying to resolve before returning it.
* This essentially makes registration optional for resolving by concerete types.
* Resolinvg will still fail when trying to resolve a dependency by supertype.
*/
registerBeforeResolving
}
/** /**
* The dependency container maintains all dependencies registered with it. * The dependency container maintains all dependencies registered with it.
* *
@ -77,6 +89,7 @@ synchronized class DependencyContainer {
private Registration[] autowireStack; private Registration[] autowireStack;
private RegistrationOption[] persistentRegistrationOptions; private RegistrationOption[] persistentRegistrationOptions;
private ResolveOption[] persistentResolveOptions;
/** /**
* Register a dependency by concrete class type. * Register a dependency by concrete class type.
@ -155,10 +168,12 @@ synchronized class DependencyContainer {
private bool hasOption(OptionType)(OptionType[] options, shared(OptionType[]) persistentOptions, OptionType option) { private bool hasOption(OptionType)(OptionType[] options, shared(OptionType[]) persistentOptions, OptionType option) {
foreach (presentOption; persistentOptions) { foreach (presentOption; persistentOptions) {
static if (is(OptionType == RegistrationOption)) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON) // DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) { if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration; presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
} }
}
if (presentOption == option) { if (presentOption == option) {
return true; return true;
@ -166,10 +181,12 @@ synchronized class DependencyContainer {
} }
foreach(presentOption ; options) { foreach(presentOption ; options) {
static if (is(OptionType == RegistrationOption)) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON) // DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) { if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration; presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
} }
}
if (presentOption == option) { if (presentOption == option) {
return true; return true;
@ -237,8 +254,8 @@ synchronized class DependencyContainer {
* --- * ---
* You need to use the resolve method which allows you to specify a qualifier. * You need to use the resolve method which allows you to specify a qualifier.
*/ */
public RegistrationType resolve(RegistrationType)() { public RegistrationType resolve(RegistrationType)(ResolveOption[] resolveOptions = []) {
return resolve!(RegistrationType, RegistrationType)(); return resolve!(RegistrationType, RegistrationType)(resolveOptions);
} }
/** /**
@ -267,7 +284,7 @@ synchronized class DependencyContainer {
* container.resolve!(Animal, Dog); * container.resolve!(Animal, Dog);
* --- * ---
*/ */
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)() { public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption[] resolveOptions = []) {
TypeInfo resolveType = typeid(RegistrationType); TypeInfo resolveType = typeid(RegistrationType);
TypeInfo qualifierType = typeid(QualifierType); TypeInfo qualifierType = typeid(QualifierType);
@ -275,6 +292,12 @@ synchronized class DependencyContainer {
writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString()); writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
} }
static if (__traits(compiles, new QualifierType())) {
if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.registerBeforeResolving)) {
register!(RegistrationType, QualifierType)();
}
}
auto candidates = resolveType in registrations; auto candidates = resolveType in registrations;
if (!candidates) { if (!candidates) {
throw new ResolveException("Type not registered.", resolveType); throw new ResolveException("Type not registered.", resolveType);

View file

@ -627,4 +627,11 @@ version(unittest) {
container.register!(TestInterface, TestClass); container.register!(TestInterface, TestClass);
container.resolve!TestClass; container.resolve!TestClass;
} }
// Test registration when resolving
unittest {
shared(DependencyContainer) container = new DependencyContainer();
container.resolve!(TestInterface, TestClass)([ResolveOption.registerBeforeResolving]);
container.resolve!TestClass;
}
} }