Add ability to resolve type which has multiple registrations by qualifier

This commit is contained in:
Mike Bierlee 2014-11-27 00:33:13 +01:00
parent d6e3043c7d
commit 8b9c8d2774
3 changed files with 70 additions and 14 deletions

View file

@ -53,10 +53,13 @@ class DependencyContainer {
writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString()));
}
auto existingRegistration = getRegistration(registeredType, concreteType);
auto existingCandidates = registeredType in registrations;
if (existingCandidates) {
auto existingRegistration = getRegistration(*existingCandidates, concreteType);
if (existingRegistration) {
return existingRegistration;
}
}
Registration newRegistration = new Registration(registeredType, concreteType);
newRegistration.singleInstance();
@ -64,23 +67,27 @@ class DependencyContainer {
return newRegistration;
}
private Registration getRegistration(TypeInfo registeredType, TypeInfo_Class concreteType) {
auto existingCandidates = registeredType in registrations;
if (existingCandidates) {
foreach(existingRegistration ; *existingCandidates) {
private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) {
foreach(existingRegistration ; candidates) {
writeln("DEBUG: Test type " ~ existingRegistration.instantiatableType.toString() ~ " with " ~ concreteType.toString());
if (existingRegistration.instantiatableType == concreteType) {
return existingRegistration;
}
}
}
return null;
}
public RegistrationType resolve(RegistrationType)() {
return resolve!(RegistrationType, RegistrationType)();
}
public RegistrationType resolve(RegistrationType, QualifierType : RegistrationType)() {
TypeInfo resolveType = typeid(RegistrationType);
TypeInfo qualifierType = typeid(QualifierType);
debug {
writeln("DEBUG: Resolving type " ~ resolveType.toString());
writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
}
auto candidates = resolveType in registrations;
@ -88,8 +95,7 @@ class DependencyContainer {
throw new ResolveException("Type not registered.", resolveType);
}
auto registration = (*candidates)[0];
Registration registration = getQualifiedRegistration(resolveType, qualifierType, *candidates);
RegistrationType instance = cast(RegistrationType) registration.getInstance();
if (!autowireStack.canFind(registration)) {
@ -101,6 +107,19 @@ class DependencyContainer {
return instance;
}
private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) {
if (resolveType == qualifierType) {
if (candidates.length > 1) {
string candidateList = candidates.toConcreteTypeListString();
throw new ResolveException("Multiple qualified candidates available: " ~ candidateList ~ ". Please specify qualifier.", resolveType);
}
return candidates[0];
}
return getRegistration(candidates, qualifierType);
}
public void clearAllRegistrations() {
registrations.destroy();
}

View file

@ -119,3 +119,14 @@ public Registration existingInstance(Registration registration, Object instance)
registration.registationScope = new ExistingInstanceScope(instance);
return registration;
}
public string toConcreteTypeListString(Registration[] registrations) {
auto concreteTypeListString = "";
foreach (registration ; registrations) {
if (!concreteTypeListString.length) {
concreteTypeListString ~= ", ";
}
concreteTypeListString ~= registration.instantiatableType.toString();
}
return concreteTypeListString;
}

View file

@ -290,4 +290,30 @@ version(unittest) {
assert(firstRegistration is secondRegistration, "First registration is not the same as the second of equal types");
}
// Test resolve registration with multiple qualifiers
unittest {
auto container = new DependencyContainer();
container.register!(Color, Blue);
container.register!(Color, Red);
try {
container.resolve!Color;
} catch (ResolveException e) {
return;
}
assert(false);
}
// Test resolve registration with multiple qualifiers using a qualifier
unittest {
auto container = new DependencyContainer();
container.register!(Color, Blue);
container.register!(Color, Red);
auto blueInstance = container.resolve!(Color, Blue);
auto redInstance = container.resolve!(Color, Red);
assert(blueInstance !is redInstance, "Resolving type with multiple, different registrations yielded the same instance");
assert(blueInstance !is null, "Resolved blue instance to null");
assert(redInstance !is null, "Resolved red instance to null");
}
}