Merge pull request #28 from huntlabs/develop

Instance initialization improved
This commit is contained in:
Mike Bierlee 2020-03-18 21:25:02 +03:00 committed by GitHub
commit 7a26dd12e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 103 additions and 15 deletions

View file

@ -36,9 +36,17 @@ class Calendar {
} }
} }
import std.stdio;
class HardwareClock { class HardwareClock {
// Parameterless constructors will halt any further selection of constructors. // Parameterless constructors will halt any further selection of constructors.
this() {} this() {
writeln("default constructor");
}
this(string name) {
writeln(name);
}
// As a result, this constructor will not be used when HardwareClock is created. // As a result, this constructor will not be used when HardwareClock is created.
this(Calendar calendar) { this(Calendar calendar) {
@ -46,7 +54,6 @@ class HardwareClock {
} }
public void doThings() { public void doThings() {
import std.stdio;
writeln("Things are being done!"); writeln("Things are being done!");
} }
} }
@ -57,7 +64,10 @@ void main() {
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
dependencies.register!Scheduler; dependencies.register!Scheduler;
dependencies.register!Calendar; dependencies.register!Calendar;
dependencies.register!HardwareClock; dependencies.register!HardwareClock( {
writeln("Running the creator");
return new HardwareClock("clock name");
});
auto scheduler = dependencies.resolve!Scheduler; auto scheduler = dependencies.resolve!Scheduler;
scheduler.scheduleJob(); scheduler.scheduleJob();

View file

@ -42,8 +42,14 @@ class AClass {
public void main() { public void main() {
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ADependency; container.register!(ADependency).onConstructed((Object obj) {
container.register!AClass; writeln("ADependency constructed");
});
container.register!(AClass).onConstructed((Object obj) {
writeln("AClass constructed");
});
auto instance = container.resolve!AClass; // Will cause the post constructor to be called. auto instance = container.resolve!AClass; // Will cause the post constructor to be called.
container.removeRegistration!AClass; // Will cause the pre destructor to be called. container.removeRegistration!AClass; // Will cause the pre destructor to be called.

View file

@ -267,9 +267,10 @@ class AutowiredRegistration(RegistrationType : Object) : Registration {
void delegate() preDestructor = null; void delegate() preDestructor = null;
foreach (memberName; __traits(allMembers, RegistrationType)) { foreach (memberName; __traits(allMembers, RegistrationType)) {
mixin(createImportsString!RegistrationType); mixin(createImportsString!RegistrationType);
enum QualifiedName = fullyQualifiedName!RegistrationType ~ `.` ~ memberName;
static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName)))
&& __traits(getProtection, __traits(getMember, instance, memberName)) == "public" && __traits(getProtection, __traits(getMember, instance, memberName)) == "public"
&& isFunction!(mixin(fullyQualifiedName!RegistrationType ~ `.` ~ memberName)) && isFunction1!(mixin(QualifiedName))
&& hasUDA!(__traits(getMember, instance, memberName), PreDestroy)) { && hasUDA!(__traits(getMember, instance, memberName), PreDestroy)) {
preDestructor = &__traits(getMember, instance, memberName); preDestructor = &__traits(getMember, instance, memberName);
} }

View file

@ -30,6 +30,8 @@ debug {
import std.stdio; import std.stdio;
} }
alias InjectionInitializer(T) = T delegate();
/** /**
* Exception thrown when errors occur while resolving a type in a dependency container. * Exception thrown when errors occur while resolving a type in a dependency container.
*/ */
@ -147,6 +149,11 @@ synchronized class DependencyContainer {
return register!(ConcreteType, ConcreteType)(options); return register!(ConcreteType, ConcreteType)(options);
} }
Registration register(ConcreteType)(InjectionInitializer!ConcreteType creator,
RegistrationOption options = RegistrationOption.none) {
return register!(ConcreteType, ConcreteType)(creator, options);
}
/** /**
* Register a dependency by super type. * Register a dependency by super type.
* *
@ -164,7 +171,9 @@ synchronized class DependencyContainer {
* *
* See_Also: singleInstance, newInstance, existingInstance, RegistrationOption * See_Also: singleInstance, newInstance, existingInstance, RegistrationOption
*/ */
public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption options = RegistrationOption.none) if (!is(ConcreteType == struct)) { public Registration register(SuperType, ConcreteType : SuperType)(
RegistrationOption options = RegistrationOption.none) if (!is(ConcreteType == struct)) {
TypeInfo registeredType = typeid(SuperType); TypeInfo registeredType = typeid(SuperType);
TypeInfo_Class concreteType = typeid(ConcreteType); TypeInfo_Class concreteType = typeid(ConcreteType);
@ -192,6 +201,44 @@ synchronized class DependencyContainer {
return newRegistration; return newRegistration;
} }
/**
*
*/
Registration register(SuperType, ConcreteType : SuperType)(InjectionInitializer!ConcreteType creator,
RegistrationOption options = RegistrationOption.none) if (!is(ConcreteType == struct)) {
TypeInfo registeredType = typeid(SuperType);
TypeInfo_Class concreteType = typeid(ConcreteType);
debug(poodinisVerbose) {
writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString()));
}
auto existingRegistration = getExistingRegistration(registeredType, concreteType);
if (existingRegistration) {
return existingRegistration;
}
InstanceFactory instanceFactory = new class InstanceFactory {
protected override Object createInstance() {
return creator();
}
};
auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, instanceFactory, this);
newRegistration.singleInstance();
static if (!is(SuperType == ConcreteType)) {
if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) {
auto concreteTypeRegistration = register!ConcreteType;
concreteTypeRegistration.linkTo(newRegistration);
}
}
registrations[registeredType] ~= cast(shared(Registration)) newRegistration;
return newRegistration;
}
private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) { private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) {
return ((options | persistentOptions) & option) != 0; return ((options | persistentOptions) & option) != 0;
} }
@ -326,6 +373,12 @@ synchronized class DependencyContainer {
} }
} }
bool isRegistered(RegistrationType)() {
TypeInfo typeInfo = typeid(RegistrationType);
auto candidates = typeInfo in registrations;
return candidates !is null;
}
private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) { private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) {
QualifierType instance; QualifierType instance;
if (!(cast(Registration[]) autowireStack).canFind(registration)) { if (!(cast(Registration[]) autowireStack).canFind(registration)) {
@ -393,10 +446,10 @@ synchronized class DependencyContainer {
private void callPostConstructors(Type)(Type instance) { private void callPostConstructors(Type)(Type instance) {
foreach (memberName; __traits(allMembers, Type)) { foreach (memberName; __traits(allMembers, Type)) {
mixin(createImportsString!Type); mixin(createImportsString!Type);
enum QualifiedName = fullyQualifiedName!Type ~ `.` ~ memberName;
static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName))) static if (__traits(compiles, __traits(getProtection, __traits(getMember, instance, memberName)))
&& __traits(getProtection, __traits(getMember, instance, memberName)) == "public" && __traits(getProtection, __traits(getMember, instance, memberName)) == "public"
&& isFunction!(mixin(fullyQualifiedName!Type ~ `.` ~ memberName)) && isFunction1!(mixin(QualifiedName))
&& hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) { && hasUDA!(__traits(getMember, instance, memberName), PostConstruct)) {
__traits(getMember, instance, memberName)(); __traits(getMember, instance, memberName)();
} }

View file

@ -22,6 +22,7 @@ import std.stdio;
alias CreatesSingleton = Flag!"CreatesSingleton"; alias CreatesSingleton = Flag!"CreatesSingleton";
alias InstanceFactoryMethod = Object delegate(); alias InstanceFactoryMethod = Object delegate();
alias InstanceEventHandler = void delegate(Object instance);
class InstanceCreationException : Exception { class InstanceCreationException : Exception {
this(string message, string file = __FILE__, size_t line = __LINE__) { this(string message, string file = __FILE__, size_t line = __LINE__) {
@ -39,6 +40,7 @@ struct InstanceFactoryParameters {
class InstanceFactory { class InstanceFactory {
private Object instance = null; private Object instance = null;
private InstanceFactoryParameters _factoryParameters; private InstanceFactoryParameters _factoryParameters;
private InstanceEventHandler _constructionHandler;
this() { this() {
factoryParameters = InstanceFactoryParameters(); factoryParameters = InstanceFactoryParameters();
@ -75,9 +77,17 @@ class InstanceFactory {
} }
instance = _factoryParameters.factoryMethod(); instance = _factoryParameters.factoryMethod();
if(_constructionHandler !is null) {
_constructionHandler(instance);
}
return instance; return instance;
} }
void onConstructed(InstanceEventHandler handler) {
_constructionHandler = handler;
}
private void printDebugUseExistingInstance() { private void printDebugUseExistingInstance() {
if (_factoryParameters.instanceType !is null) { if (_factoryParameters.instanceType !is null) {
writeln(format("DEBUG: Existing instance returned of type %s", _factoryParameters.instanceType.toString())); writeln(format("DEBUG: Existing instance returned of type %s", _factoryParameters.instanceType.toString()));

View file

@ -43,21 +43,24 @@ static if (!__traits(compiles, basicExceptionCtors)) {
} }
} }
static if (!__traits(compiles, isFunction)) { static if (!__traits(compiles, isFunction1)) {
template isFunction(X...) if (X.length == 1) template isFunction1(X...)
{ {
static if (X.length > 1) {
enum isFunction1 = false;
} else
static if (is(typeof(&X[0]) U : U*) && is(U == function) || static if (is(typeof(&X[0]) U : U*) && is(U == function) ||
is(typeof(&X[0]) U == delegate)) is(typeof(&X[0]) U == delegate))
{ {
// x is a (nested) function symbol. // x is a (nested) function symbol.
enum isFunction = true; enum isFunction1 = true;
} }
else static if (is(X[0] T)) else static if (is(X[0] T))
{ {
// x is a type. Take the type of it and examine. // x is a type. Take the type of it and examine.
enum isFunction = is(T == function); enum isFunction1 = is(T == function);
} }
else else
enum isFunction = false; enum isFunction1 = false;
} }
} }

View file

@ -60,7 +60,6 @@ class Registration {
return linkedRegistration.getInstance(context); return linkedRegistration.getInstance(context);
} }
if (instanceFactory is null) { if (instanceFactory is null) {
throw new InstanceCreationException("No instance factory defined for registration of type " ~ registeredType.toString()); throw new InstanceCreationException("No instance factory defined for registration of type " ~ registeredType.toString());
} }
@ -72,6 +71,12 @@ class Registration {
this.linkedRegistration = registration; this.linkedRegistration = registration;
return this; return this;
} }
Registration onConstructed(InstanceEventHandler handler) {
if(instanceFactory !is null)
instanceFactory.onConstructed(handler);
return this;
}
} }
/** /**