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
|
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**
|
**Version 2.0.0**
|
||||||
This version introduces changes which might be incompatible with your current codebase
|
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.
|
* 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;
|
auto exampleClassInstance2 = dependencies.resolve!ExampleInterface;
|
||||||
assert(exampleClassInstance !is exampleClassInstance2);
|
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
|
###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:
|
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.
|
* The dependency container maintains all dependencies registered with it.
|
||||||
*
|
*
|
||||||
|
@ -63,11 +98,7 @@ synchronized class DependencyContainer {
|
||||||
* Register and resolve a class by concrete type:
|
* Register and resolve a class by concrete type:
|
||||||
* ---
|
* ---
|
||||||
* class Cat : Animal { ... }
|
* class Cat : Animal { ... }
|
||||||
*
|
|
||||||
* container.register!Cat;
|
* container.register!Cat;
|
||||||
*
|
|
||||||
* container.resolve!Cat;
|
|
||||||
* container.resolve!(Animal, Cat); // Error! dependency is not registered by super type.
|
|
||||||
* ---
|
* ---
|
||||||
*
|
*
|
||||||
* See_Also: singleInstance, newInstance, existingInstance
|
* See_Also: singleInstance, newInstance, existingInstance
|
||||||
|
@ -88,16 +119,12 @@ synchronized class DependencyContainer {
|
||||||
* Register and resolve by super type
|
* Register and resolve by super type
|
||||||
* ---
|
* ---
|
||||||
* class Cat : Animal { ... }
|
* class Cat : Animal { ... }
|
||||||
*
|
|
||||||
* container.register!(Animal, Cat);
|
* 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 registeredType = typeid(SuperType);
|
||||||
TypeInfo_Class concreteType = typeid(ConcreteType);
|
TypeInfo_Class concreteType = typeid(ConcreteType);
|
||||||
|
|
||||||
|
@ -112,10 +139,30 @@ synchronized class DependencyContainer {
|
||||||
|
|
||||||
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, this);
|
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, this);
|
||||||
newRegistration.singleInstance();
|
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;
|
registrations[registeredType] ~= cast(shared(Registration)) newRegistration;
|
||||||
return 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) {
|
private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) {
|
||||||
auto existingCandidates = registrationType in registrations;
|
auto existingCandidates = registrationType in registrations;
|
||||||
if (existingCandidates) {
|
if (existingCandidates) {
|
||||||
|
|
|
@ -426,4 +426,21 @@ version(unittest) {
|
||||||
|
|
||||||
assert(expectedTestClass is actualTestClass, "Instance resolved in main thread is not the one resolved in thread");
|
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