This is my second attempt to explain what I am trying to accomplish as I did not explain it very well before.
for this Pseudo example if you have the classes to resolve setup as below;
TOuter.constructor.Create(Name: TName; Inner1, Inner2: TInner);
TInner.constructor.Create(Name: TName; Sub: TSub);
TSub.constructor.Create(Name: TName);
TName.constructor.Create(Name: String);
var Names = TStack<String>.Create;
If it is possible to intercept before and after resolve it would be possible to implement a parent, ancestor or, 'i am being constructed for ...'.
for example
RegisterType<TName>(
function: TName
begin
Result:=TName.Create(String.Join('.',Names.List.ToArray));
end
);
RegisterType<TOuter>;
RegisterType<TInner>;
RegisterType<TSub>;
Resolver.BeforeResolve:=
procedure(ClassType: TClass)
begin
Names.Push(ClassType.ClassName);
end;
Resolver.AfterResolve:=
procedure(ClassType: TClass)
begin
Names.Pop;
end;
Resolve<TOuter> would produce
TOuter
Name = 'Outer'
Inner1 =
Name = 'Outer.Inner'
Sub
Name = 'Outer.Inner.Sub'
Inner2
Name = 'Outer.Inner'
Sub
Name = 'Outer.Inner.Sub'
I did think it might be possible by sub classing the component activator and looking for if classname=TName or if arguments.contains(TName) then ...
For this example I have omitted making the Names stack handle multiple threads and in reality I am not using names but rather having a stack of interfaces each knowing who their 'parent' is but this demonstrates what I am trying to implement.
Instance creation is ultimately done within the component activator. If you create a decorator for that you can solve your requirement.
I will just write down the code - you can package this into a container extension that does all the stuff automatically (look into the Spring.Container.*Extension
units).
For brevity, I will leave out all standard creation and cleanup code and any code to make this thread-safe.
type
TComponentActivatorDecorator = class(TInterfacedObject, IComponentActivator)
private
fActivator: IComponentActivator;
public
constructor Create(const activator: IComponentActivator);
function CreateInstance(const context: ICreationContext): TValue;
end;
type
TComponentActivatorBaseAccess = class(
Spring.Container.ComponentActivator.TComponentActivatorBase)
end;
function TComponentActivatorDecorator.CreateInstance(
const context: ICreationContext): TValue;
var
name: string;
begin
// yes, this is a bit ugly because the information about the handled type
// is not passed to the method but a protected state of the activator
// actually this should (and actually is but only internally) be part of
// the ICreationContext - this might change in the future
name := TComponentActivatorBaseAccess(TObject(fActivator)).Model.ComponentType.Name;
Names.Push(name);
try
Result := fActivator.CreateInstance(context);
finally
Names.Pop
end;
end;
After the call to Build
you run this code:
for Model in GlobalContainer.Registry.FindAll() do
begin
if Model.ComponentActivator is TReflectionComponentActivator then
Model.ComponentActivator := TComponentActivatorDecorator.Create(Model.ComponentActivator);
end;
Now every activator that does the object creation via reflection (so not the ones doing by a delegate) is being decorated and executes the extra push/pop logic and you access that in your TName
delegate.
I declared TName as follows:
type
TName = type string;
and its registration:
GlobalContainer.RegisterType<TName>(
function: TName
begin
Result := string.Join('.',Names.ToArray);
end);
Here is how a resolved TOuter instance looks now: