TVirtualMethodInterceptor cannot be used for AfterConstruction

skybuck2000 <[email protected]> Sun, 30 Jan 2022 14:32:25 -0800 (PST)
Newsgroups alt.comp.lang.borland-delphi
Message-ID <[email protected]>
If TStream.AfterConstruction could be overriden then all stream objects could be captured, actually all objects could be captured.

Unfortunately VirtualMethodInterception seems to be wrongly designed and can only act on already existing instances, instead of a class.

This example from the documentation completely ignores construction of objects and therefore the AfterConstruction method which is also virtual:

(See down below for suggestion how to fix Delphi in future):

uses
  SysUtils,
  Rtti;

type
  TFoo = class
    // Frob doubles x and returns the new x + 10
    function Frob(var x: Integer): Integer; virtual;
  end;

function TFoo.Frob(var x: Integer): Integer;
begin
  x := x * 2;
  Result := x + 10;
end;

procedure WorkWithFoo(Foo: TFoo);
var
  a, b: Integer;
begin
  a := 10;
  Writeln('  [WorkWithFoo] before: a = ', a);
  try
    b := Foo.Frob(a);
    Writeln('  [WorkWithFoo] Result = ', b);
    Writeln('  [WorkWithFoo] after:  a = ', a);
  except
    on e: Exception do
      Writeln('  Exception: ', e.ClassName);
  end;
end;

procedure P;
var
  foo: TFoo;
  vmi: TVirtualMethodInterceptor;
begin
  vmi := nil;
  foo := TFoo.Create;
  try
    Writeln('Before hackery:');
    WorkWithFoo(foo);

    vmi := TVirtualMethodInterceptor.Create(foo.ClassType);

    vmi.OnBefore := procedure(Instance: TObject; Method: TRttiMethod;
      const Args: TArray<TValue>; out DoInvoke: Boolean; out Result: TValue)
    var
      i: Integer;
    begin
      Write('[OnBefore] Calling ', Method.Name, ' with args: ');
      for i := 0 to Length(Args) - 1 do
        Write(Args[i].ToString, ' ');
      Writeln;
    end;

    // Change foo's metaclass pointer to our new dynamically derived
    // and intercepted descendant
    vmi.Proxify(foo);

    Writeln('After interception:');
    WorkWithFoo(foo);
  finally
    foo.Free;
    vmi.Free;
  end;
end;

begin
  P;
  readln; // To see what's in console before it goes away.
end.

This should be fixed in a subsequent version of Delphi if possible.


Main issue seems to be:

procedure Proxify(AInstance: TObject);

It should be possible to pass a class as well.

And then call some kind of constructor or other method to create these derived instances.

So that AfterConstruction can also be intercepted !

Bye,
  Skybuck.