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,9 +53,12 @@ class DependencyContainer {
writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString())); writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString()));
} }
auto existingRegistration = getRegistration(registeredType, concreteType); auto existingCandidates = registeredType in registrations;
if (existingRegistration) { if (existingCandidates) {
return existingRegistration; auto existingRegistration = getRegistration(*existingCandidates, concreteType);
if (existingRegistration) {
return existingRegistration;
}
} }
Registration newRegistration = new Registration(registeredType, concreteType); Registration newRegistration = new Registration(registeredType, concreteType);
@ -64,13 +67,11 @@ class DependencyContainer {
return newRegistration; return newRegistration;
} }
private Registration getRegistration(TypeInfo registeredType, TypeInfo_Class concreteType) { private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) {
auto existingCandidates = registeredType in registrations; foreach(existingRegistration ; candidates) {
if (existingCandidates) { writeln("DEBUG: Test type " ~ existingRegistration.instantiatableType.toString() ~ " with " ~ concreteType.toString());
foreach(existingRegistration ; *existingCandidates) { if (existingRegistration.instantiatableType == concreteType) {
if (existingRegistration.instantiatableType == concreteType) { return existingRegistration;
return existingRegistration;
}
} }
} }
@ -78,9 +79,15 @@ class DependencyContainer {
} }
public RegistrationType resolve(RegistrationType)() { public RegistrationType resolve(RegistrationType)() {
return resolve!(RegistrationType, RegistrationType)();
}
public RegistrationType resolve(RegistrationType, QualifierType : RegistrationType)() {
TypeInfo resolveType = typeid(RegistrationType); TypeInfo resolveType = typeid(RegistrationType);
TypeInfo qualifierType = typeid(QualifierType);
debug { debug {
writeln("DEBUG: Resolving type " ~ resolveType.toString()); writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
} }
auto candidates = resolveType in registrations; auto candidates = resolveType in registrations;
@ -88,8 +95,7 @@ class DependencyContainer {
throw new ResolveException("Type not registered.", resolveType); throw new ResolveException("Type not registered.", resolveType);
} }
auto registration = (*candidates)[0]; Registration registration = getQualifiedRegistration(resolveType, qualifierType, *candidates);
RegistrationType instance = cast(RegistrationType) registration.getInstance(); RegistrationType instance = cast(RegistrationType) registration.getInstance();
if (!autowireStack.canFind(registration)) { if (!autowireStack.canFind(registration)) {
@ -101,6 +107,19 @@ class DependencyContainer {
return instance; 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() { public void clearAllRegistrations() {
registrations.destroy(); registrations.destroy();
} }

View file

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

View file

@ -172,7 +172,7 @@ version(unittest) {
auto autowiredInstance = container.resolve!AutowiredClass; auto autowiredInstance = container.resolve!AutowiredClass;
assert(componentInstance.autowiredClass is autowiredInstance, "Member is not autowired upon resolving"); assert(componentInstance.autowiredClass is autowiredInstance, "Member is not autowired upon resolving");
} }
// Test circular autowiring // Test circular autowiring
unittest { unittest {
auto container = new DependencyContainer(); auto container = new DependencyContainer();
@ -290,4 +290,30 @@ version(unittest) {
assert(firstRegistration is secondRegistration, "First registration is not the same as the second of equal types"); 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");
}
} }