Skip to content

Instantly share code, notes, and snippets.

@dipold
Last active July 13, 2018 14:37
Show Gist options
  • Save dipold/7b871788222dd7eb94962a9cc92d2e9a to your computer and use it in GitHub Desktop.
Save dipold/7b871788222dd7eb94962a9cc92d2e9a to your computer and use it in GitHub Desktop.
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Rtti,
System.SysUtils,
System.TypInfo;
type
IFoo = interface(IInvokable)
['{22C53437-C1E8-4A3D-B397-4F041743AD84}']
function GetValue: String;
procedure SetValue(const AValue: String);
property Value: String read GetValue write SetValue;
end;
{$RTTI EXPLICIT METHODS([vcPrivate])}
TFoo = class(TInterfacedObject, IFoo)
strict private
FValue: String;
function GetValue: String;
procedure SetValue(const AValue: String);
public
property Value: String read GetValue write SetValue;
end;
TProxy<T: IInvokable> = class(TVirtualInterface)
strict private
FRealInstance: T;
FLoaded: Boolean;
procedure VirtualInterfaceInvokeEvent(AMethod: TRttiMethod; const AArgs: TArray<TValue>; out OResult: TValue);
public
constructor Create(const AStubInstance: T);
end;
constructor TProxy<T>.Create(const AStubInstance: T);
begin
inherited Create(TypeInfo(T), VirtualInterfaceInvokeEvent);
FLoaded := False;
FRealInstance := AStubInstance;
end;
procedure TProxy<T>.VirtualInterfaceInvokeEvent(AMethod: TRttiMethod; const AArgs: TArray<TValue>; out OResult: TValue);
var
LContext: TRttiContext;
LArgs: TArray<TValue>;
LObject: TObject;
LMethod: TRttiMethod;
I: Integer;
begin
LArgs := Copy(AArgs, 1);
if (not FLoaded) then
begin
//FRealInstance := DAOManager<T>.GetFoo.FromDatabase;
FLoaded := True;
end;
//There are a best way to invoke AMethod from FRealInstance?
//It seems a little expensive to do this way
LObject := FRealInstance as TObject;
for LMethod in LContext.GetType(LObject.ClassInfo).GetMethods do
begin
if (CompareText(LMethod.Name, AMethod.Name) = 0) then
begin
if (Length(LMethod.GetParameters) = Length(AMethod.GetParameters)) then
begin
for I := 0 to Pred(Length(LMethod.GetParameters)) do
if (LMethod.GetParameters[I].ParamType.TypeKind <> AMethod.GetParameters[I].ParamType.TypeKind) then
Continue;
OResult := LMethod.Invoke(LObject, LArgs);
Break;
end;
end;
end;
end;
{ TFoo }
function TFoo.GetValue: String;
begin
Result := FValue;
end;
procedure TFoo.SetValue(const AValue: String);
begin
FValue := AValue;
end;
var
ProxyFoo: IFoo;
begin
ProxyFoo := TProxy<IFoo>.Create(TFoo.Create) as IFoo;
ProxyFoo.Value := 'Bar';
WriteLn('Value: ', ProxyFoo.Value);
ProxyFoo.Value := 'Xyzzy';
WriteLn('Value: ', ProxyFoo.Value);
ReadLn;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment