首页 > 解决方案 > Delphi如何检查IInterface的实例是否是IInvokable

问题描述

我想在我的接口实例上做一个包装器,我打算使用 TVirtualInterface 类来做到这一点,但它只接受 IInvokable 实例,有什么办法可以实现 IsInterfaceIInvokable 函数,以便它返回给我,如果过去的实例是否是 IInvokable 实例?

代码:

program InterfaceWrapper;

{$APPTYPE CONSOLE}

{$R *.res}


uses
   System.SysUtils,
   System.TypInfo,
   System.Rtti;

type
   IMinhaInterface = interface(IInvokable)
      ['{1DFA8F7B-57BF-44E5-BBBF-76492EE36CEA}']
      procedure Fazer;
   end;

   TMinhaInterfaceImp = class(TInterfacedObject, IMinhaInterface)
   public
      procedure Fazer;
   end;

   TWrapper = class(TVirtualInterface)
   private
      intF: IInterface;
   public
      constructor Create(const PIID: PTypeInfo; const intF: IInterface);
   end;

   { TMinhaInterfaceImp }

procedure TMinhaInterfaceImp.Fazer;
begin
   Writeln('procedure TMinhaInterfaceImp.Fazer');
end;

{ TWrapper }

constructor TWrapper.Create(const PIID: PTypeInfo; const intF: IInterface);
begin
   inherited Create(PIID);
   Self.intF := intF;
   Self.OnInvoke := procedure(Method: TRttiMethod; const Args: TArray<TValue>; out Result: TValue)
      begin
         try
            Writeln('Antes');
            Result := Method.Invoke(TValue.From(Self.intF), Copy(Args, 1, Length(Args) - 1));
            Writeln('Depois');
         except
            on E: Exception do
            begin
               Writeln(E.ClassName, ': ', E.Message);
            end;
         end;
      end;
end;

function IsInterfaceIInvokable(const intF: IInterface; const PIID: PTypeInfo): Boolean;
begin
   Result := intF is IInvokable;
end;

begin
   try
      var intF := TMinhaInterfaceImp.Create as IMinhaInterface;

      if IsInterfaceIInvokable(intF, TypeInfo(IMinhaInterface)) then
      begin
         intF := TWrapper.Create(TypeInfo(IMinhaInterface), intF) as IMinhaInterface;
      end;

      intF.Fazer;

      var str: string;
      Readln(str);
   except
      on E: Exception do
         Writeln(E.ClassName, ': ', E.Message);
   end;

end.

标签: delphi

解决方案


中有未记录的枚举值System.TypInfo.TIntfFlag(请参阅RSP-24631

所以你可以使用这个代码——不仅接口继承自,IInvokable而且如果它有{$M+}

function HasMethodInfo(typeInfo: PTypeInfo): Boolean;
type
  TIntfFlagEx = (ifHasGuid, ifDispInterface, ifDispatch, ifMethodInfo);
  TIntfFlagsEx = set of TIntfFlagEx;
begin
  Result := Assigned(typeInfo) and (typeInfo.Kind = tkInterface)
    and (ifMethodInfo in TIntfFlagsEx(typeInfo.TypeData.IntfFlags));
end;

推荐阅读