delphi Spring 4D中的BeforeResolve/AfterResolve

3phpmpom  于 2023-03-22  发布在  Spring
关注(0)|答案(1)|浏览(151)

这是我第二次尝试解释我试图完成的事情,因为我以前没有解释得很好。
对于这个伪例子,如果你有类来解决安装如下;

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;

如果可以在解析之前和之后进行拦截,则可以实现父代、祖先或“正在为……构造我”。
例如

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'

我确实认为可以通过子类化组件激活器并查找if classname=TName或if arguments.contains(TName)然后...
在这个例子中,我省略了让Names堆栈处理多个线程,实际上我没有使用名称,而是有一个接口堆栈,每个接口都知道他们的“父”是谁,但这表明了我试图实现的东西。

fafcakar

fafcakar1#

示例的创建最终是在组件激活器中完成的。如果你为它创建一个装饰器,你就可以解决你的需求。
我将写下代码-您可以将其打包到自动完成所有工作的容器扩展中(查看Spring.Container.*Extension单元)。
为了简洁起见,我将省略所有标准的创建和清理代码以及任何使此线程安全的代码。

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;

调用Build后,运行以下代码:

for Model in GlobalContainer.Registry.FindAll() do
  begin
    if Model.ComponentActivator is TReflectionComponentActivator then
      Model.ComponentActivator := TComponentActivatorDecorator.Create(Model.ComponentActivator);
  end;

现在,每个通过反射创建对象的激活器(所以不是由委托创建的)都被修饰,并执行额外的推/弹出逻辑,您可以在TName委托中访问该逻辑。
我声明TName如下:

type
  TName = type string;

及其注册:

GlobalContainer.RegisterType<TName>(
  function: TName
  begin
    Result := string.Join('.',Names.ToArray);
  end);

下面是一个解析后的Touter示例的外观:

相关问题