1

Goals:

  • In the Delphi programming language.
  • An aspect that intercepts all virtual methods.
  • A class whose constructor requires arguments.
  • A Dependency Injection (DI) container that BOTH
    • Creates an instance of the class, passing the correct arguments to the constructor.
    • Applies the aspect to the instance so that all calls to virtual methods on the instance are intercepted.

I have made an attempt to do this with the Spring4D Container and Interception abstractions:

The below code outputs nothing. I would like similar code that outputs:

Intercepted one
Intercepted two
Intercepted three
unit Main;

interface

uses
  Spring.Container,
  Spring.Interception,
  Spring.Services;

procedure Run;

type
  TAspect = class(TInterfacedObject, IInterceptor)
  public
    procedure Intercept(const Invocation: IInvocation);
  end;
  TDependency = class(TObject)
    procedure two; virtual;
  end;
  TTarget = class(TObject)
    var FDependency: TDependency;
    constructor Create(const Dependency: TDependency);
    procedure one; virtual;
    procedure three; virtual;
  end;

implementation

procedure Run;
begin
  GlobalContainer.RegisterType<TAspect>;
  GlobalContainer.RegisterType<TDependency>.InterceptedBy<TAspect>;
  GlobalContainer.RegisterType<TTarget>.InterceptedBy<TAspect>;
  GlobalContainer.Build;
  var Target := ServiceLocator.GetService<TTarget>;
  Target.one;
end;

procedure TAspect.Intercept(const Invocation: IInvocation);
begin
  Writeln('Intecepted ' + Invocation.Method.Name);
  Invocation.Proceed;
end;

procedure TDependency.two;
begin
end;

constructor TTarget.Create(const Dependency: TDependency);
begin
  inherited Create;
  FDependency := Dependency;
end;

procedure TTarget.one;
begin
  FDependency.two;
  three;
end;

procedure TTarget.three;
begin
end;

end.

I tried something like this, and it intercepts ALL calls to virtual methods, but it doesn't meet all the goals listed above because it doesn't go through the DI container.

var Aspect: IInterceptor := TAspect.Create;
var Target := TProxyGenerator.CreateClassProxy<TTarget>([Aspect]);

I also tried using the container, but delegating to something that calls TProxyGenerator, and that intercepts ALL calls to virtual methods, but it doesn't meet all the goals listed above because it can only use the zero argument constructor (i.e. no constructor injection).

1 Answers1

1

Interceptors via InterceptedBy only get applied by the container to interface-based services as proxies. This is simply because a) there is no ambiguity in how to manage the lifetime of such and b) all method calls go through the proxy opposed to class based services where only the virtual methods get intercepted.

When this gets applied to the code above you will get output for one and two but not for three because that method gets called from within the TTarget instance.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102