mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Add registration option for registering a class by concrete type when registering by supertype
This commit is contained in:
parent
d23230faae
commit
27e7b74e73
|
@ -1,5 +1,8 @@
|
|||
Poodinis Changelog
|
||||
==================
|
||||
**Version 2.1.0**
|
||||
* ADD option for registering a class by concrete type when registering that class by supertype.
|
||||
|
||||
**Version 2.0.0**
|
||||
This version introduces changes which might be incompatible with your current codebase
|
||||
* CHANGE dependency container to be synchronized. Sharing a dependency container between threads is now possible.
|
||||
|
|
|
@ -74,6 +74,13 @@ auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
|||
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
|
||||
assert(exampleClassInstance !is exampleClassInstance2);
|
||||
```
|
||||
You can solve this by adding the ADD_CONCRETE_TYPE_REGISTRATION option when registering:
|
||||
```d
|
||||
dependencies.register!(ExampleInterface, ExampleClass)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION);
|
||||
auto exampleClassInstance = dependencies.resolve!ExampleClass;
|
||||
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
|
||||
assert(exampleClassInstance is exampleClassInstance2);
|
||||
```
|
||||
|
||||
###Dependency scopes
|
||||
With dependency scopes, you can control how a dependency is resolved. The scope determines which instance is returned, be it the same each time or a new one. The following scopes are available:
|
||||
|
|
|
@ -33,6 +33,41 @@ class ResolveException : Exception {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when errors occur while registering a type in a dependency container.
|
||||
*/
|
||||
class RegistrationException : Exception {
|
||||
this(string message, TypeInfo registrationType) {
|
||||
super(format("Exception while registering type %s: %s", registrationType.toString(), message));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options which influence the process of registering dependencies
|
||||
*/
|
||||
public enum RegistrationOptions {
|
||||
/**
|
||||
* When registering a type by its supertype, providing this option will also register
|
||||
* a linked registration to the type itself.
|
||||
*
|
||||
* This allows you to resolve that type both by super type and concrete type using the
|
||||
* same registration scope (and instance managed by this scope).
|
||||
*
|
||||
* Examples:
|
||||
* ---
|
||||
* class Cat : Animal { ... }
|
||||
*
|
||||
* container.register!(Animal, Cat)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION);
|
||||
*
|
||||
* auto firstCat = container.resolve!(Animal, Cat);
|
||||
* auto secondCat = container.resolve!Cat;
|
||||
*
|
||||
* assert(firstCat is secondCat);
|
||||
* ---
|
||||
*/
|
||||
ADD_CONCRETE_TYPE_REGISTRATION
|
||||
}
|
||||
|
||||
/**
|
||||
* The dependency container maintains all dependencies registered with it.
|
||||
*
|
||||
|
@ -63,11 +98,7 @@ synchronized class DependencyContainer {
|
|||
* Register and resolve a class by concrete type:
|
||||
* ---
|
||||
* class Cat : Animal { ... }
|
||||
*
|
||||
* container.register!Cat;
|
||||
*
|
||||
* container.resolve!Cat;
|
||||
* container.resolve!(Animal, Cat); // Error! dependency is not registered by super type.
|
||||
* ---
|
||||
*
|
||||
* See_Also: singleInstance, newInstance, existingInstance
|
||||
|
@ -88,16 +119,12 @@ synchronized class DependencyContainer {
|
|||
* Register and resolve by super type
|
||||
* ---
|
||||
* class Cat : Animal { ... }
|
||||
*
|
||||
* container.register!(Animal, Cat);
|
||||
*
|
||||
* container.resolve!(Animal, Cat);
|
||||
* container.resolve!Cat; // Error! dependency is not registered by concrete type.
|
||||
* ---
|
||||
*
|
||||
* See_Also: singleInstance, newInstance, existingInstance
|
||||
* See_Also: singleInstance, newInstance, existingInstance, RegistrationOptions
|
||||
*/
|
||||
public Registration register(SuperType, ConcreteType : SuperType)() {
|
||||
public Registration register(SuperType, ConcreteType : SuperType, RegistrationOptionsTuple...)(RegistrationOptionsTuple options) {
|
||||
TypeInfo registeredType = typeid(SuperType);
|
||||
TypeInfo_Class concreteType = typeid(ConcreteType);
|
||||
|
||||
|
@ -112,10 +139,30 @@ synchronized class DependencyContainer {
|
|||
|
||||
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, this);
|
||||
newRegistration.singleInstance();
|
||||
|
||||
if (hasOption(options, RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION)) {
|
||||
static if (!is(SuperType == ConcreteType)) {
|
||||
auto concreteTypeRegistration = register!ConcreteType;
|
||||
concreteTypeRegistration.linkTo(newRegistration);
|
||||
} else {
|
||||
throw new RegistrationException("Option ADD_CONCRETE_TYPE_REGISTRATION cannot be used when registering a concrete type registration", concreteType);
|
||||
}
|
||||
}
|
||||
|
||||
registrations[registeredType] ~= cast(shared(Registration)) newRegistration;
|
||||
return newRegistration;
|
||||
}
|
||||
|
||||
private bool hasOption(RegistrationOptionsTuple...)(RegistrationOptionsTuple options, RegistrationOptions option) {
|
||||
foreach(presentOption ; options) {
|
||||
if (presentOption == option) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) {
|
||||
auto existingCandidates = registrationType in registrations;
|
||||
if (existingCandidates) {
|
||||
|
|
|
@ -426,4 +426,21 @@ version(unittest) {
|
|||
|
||||
assert(expectedTestClass is actualTestClass, "Instance resolved in main thread is not the one resolved in thread");
|
||||
}
|
||||
|
||||
// Test registering type with option ADD_CONCRETE_TYPE_REGISTRATION
|
||||
unittest {
|
||||
shared(DependencyContainer) container = new DependencyContainer();
|
||||
container.register!(TestInterface, TestClass)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION);
|
||||
|
||||
auto firstInstance = container.resolve!TestInterface;
|
||||
auto secondInstance = container.resolve!TestClass;
|
||||
|
||||
assert(firstInstance is secondInstance);
|
||||
}
|
||||
|
||||
// Test registering concrete type with option ADD_CONCRETE_TYPE_REGISTRATION
|
||||
unittest {
|
||||
shared(DependencyContainer) container = new DependencyContainer();
|
||||
assertThrown!RegistrationException(container.register!(TestClass, TestClass)(RegistrationOptions.ADD_CONCRETE_TYPE_REGISTRATION));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue