http://docwiki.embarcadero.com/CodeExamples/XE8/en/Rtti.TVirtualInterface_(Delphi)
Чудесная штука. На ней можно делать свои интерфейсы на стороне собственных скриптов. Ну или другой мета-информации. Сами они его для SOAP используют.
А мне рассказывали про собственную реализацию интерфейсов для Delphi на стороне Python'а.
(+) http://docwiki.embarcadero.com/Libraries/XE8/en/System.Rtti.TRawVirtualClass
Интересный такой код:
Прям руки чешутся это в реальных условиях попробовать.
А в SOAP оно используется тут:
Тоже крайне забавно.
Самое, что смешное, что оно только там и используется. Хотя возможности для использования данного подхода - огромны.
Для всяческого "собственного маршалинга".
Ну и для ORM например. Хотя есть и другой путь. Несколько обратный:
http://18delphi.blogspot.ru/2013/07/blog-post.html
http://roman.yankovsky.me/?p=740
Чудесная штука. На ней можно делать свои интерфейсы на стороне собственных скриптов. Ну или другой мета-информации. Сами они его для SOAP используют.
А мне рассказывали про собственную реализацию интерфейсов для Delphi на стороне Python'а.
(+) http://docwiki.embarcadero.com/Libraries/XE8/en/System.Rtti.TRawVirtualClass
Интересный такой код:
constructor TVirtualInterface.Create(PIID: PTypeInfo); var Methods: TArray<TRttiMethod>; Method: TRttiMethod; Typ: TRttiType; MaxIndex, I: Integer; begin FIntercepts := TObjectList<TImplInfo>.Create(True); Typ := FContext.GetType(PIID); FIID := TRttiInterfaceType(Typ).GUID; Methods := Typ.GetMethods; MaxIndex := 2; // Is this the best way to do this? for Method in Methods do begin if MaxIndex < Method.VirtualIndex then MaxIndex := Method.VirtualIndex; FIntercepts.Add(TImplInfo.Create(Method, RawCallBack)); end; VTable := AllocMem(SizeOf(Pointer)* (MaxIndex+1)); PVtablePtr(VTable)[0] := @TVirtualInterface._QIFromIntf; PVtablePtr(VTable)[1] := @TVirtualInterface._AddRefFromIntf; PVtablePtr(VTable)[2] := @TVirtualInterface._ReleaseFromIntf; for I := 0 to FIntercepts.Count-1 do PVtablePtr(VTable)[FIntercepts[I].VirtualIndex] := FIntercepts[I].CodeAddress; for I := 3 to MaxIndex do if PVtablePtr(VTable)[I] = nil then PVtablePtr(VTable)[I] := @TVirtualInterface.ErrorProc; end; constructor TVirtualInterface.Create(PIID: PTypeInfo; InvokeEvent: TVirtualInterfaceInvokeEvent); begin Create(PIID); FOnInvoke := InvokeEvent; end; destructor TVirtualInterface.Destroy; begin if VTable <> nil then FreeMem(VTable); FIntercepts.Free; inherited; end; procedure TVirtualInterface.RawCallback(UserData: Pointer; const Args: TArray<TValue>; out Result: TValue); begin if Assigned(FOnInvoke) then FOnInvoke(TImplInfo(UserData).FMethod, Args, Result); end; procedure TVirtualInterface.ErrorProc; begin raise InsufficientRtti; end; function TVirtualInterface._AddRefFromIntf: Integer; begin Result := TVirtualInterface(PByte(Self) - (PByte(@Self.VTable) - PByte(Self)))._AddRef; end; function TVirtualInterface._ReleaseFromIntf: Integer; begin Result := TVirtualInterface(PByte(Self) - (PByte(@Self.VTable) - PByte(Self)))._Release; end; function TVirtualInterface._QIFromIntf(const IID: TGUID; out Obj): HResult; begin Result := TVirtualInterface(PByte(Self) - (PByte(@Self.VTable) - PByte(Self))).QueryInterface(IID, Obj); end; function TVIrtualInterface._AddRef: Integer; begin Result := inherited end; function TVIrtualInterface._Release: Integer; begin Result := inherited end; function TVirtualInterface.QueryInterface(const IID: TGUID; out Obj): HResult; begin if iid = FIID then begin _AddRef; Pointer(Obj) := @VTable; Result := S_OK; end else Result := inherited end;
Прям руки чешутся это в реальных условиях попробовать.
А в SOAP оно используется тут:
TRIO = class(TComponent, IInterface, IRIOAccess) private type TRioVirtualInterface = class(TVirtualInterface) private FRio: TRio; protected //{$IFNDEF AUTOREFCOUNT} function _AddRef: Integer; override; stdcall; function _Release: Integer; override; stdcall; //{$ENDIF !AUTOREFCOUNT} public constructor Create(ARio: TRio; AInterface: Pointer); //{$IFNDEF AUTOREFCOUNT} function QueryInterface(const IID: TGUID; out Obj): HRESULT; override; stdcall; //{$ENDIF !AUTOREFCOUNT} end; private FInterface: IInterface; {$IFNDEF AUTOREFCOUNT} FRefCount: Integer; {$ENDIF !AUTOREFCOUNT} { Headers } FSOAPHeaders: TSOAPHeaders; FHeadersOutBound: THeaderList; FHeadersInbound: THeaderList; FOnAfterExecute: TAfterExecuteEvent; FOnBeforeExecute: TBeforeExecuteEvent; FOnSendAttachment: TOnSendAttachmentEvent; FOnGetAttachment: TOnGetAttachmentEvent; procedure Generic(Method: TRttiMethod; const Args: TArray; out Result: TValue); {$IFNDEF AUTOREFCOUNT} function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; {$ENDIF !AUTOREFCOUNT} { IRIOAccess } function GetRIO: TRIO; protected FIID: TGUID; IntfMD: TIntfMetaData; FConverter: IOPConvert; FWebNode: IWebNode; procedure DoDispatch(const Context: TInvContext; MethNum: Integer; const MethMD: TIntfMethEntry); function InternalQI(const IID: TGUID; out Obj): HResult; stdcall; { Routines that derived RIOs may override } procedure DoAfterExecute(const MethodName: string; Response: TStream); virtual; procedure DoBeforeExecute(const MethodName: string; Request: TStream); virtual; function GetResponseStream(BindingType: TWebServiceBindingType): TStream; virtual; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function QueryInterface(const IID: TGUID; out Obj): HResult; override; stdcall; { Behave like a TInterfacedObject, (only when Owner = nil) } {$IFNDEF AUTOREFCOUNT} procedure AfterConstruction; override; procedure BeforeDestruction; override; class function NewInstance: TObject; override; property RefCount: Integer read FRefCount; {$ENDIF !AUTOREFCOUNT} property Converter: IOPConvert read FConverter write FConverter; property WebNode: IWebNode read FWebNode write FWebNode; property SOAPHeaders: TSOAPHeaders read FSOAPHeaders; published property OnAfterExecute: TAfterExecuteEvent read FOnAfterExecute write FOnAfterExecute; property OnBeforeExecute: TBeforeExecuteEvent read FOnBeforeExecute write FOnBeforeExecute; property OnSendAttachment: TOnSendAttachmentEvent read FOnSendAttachment write FOnSendAttachment; property OnGetAttachment: TOnGetAttachmentEvent read FOnGetAttachment write FOnGetAttachment; end;
Тоже крайне забавно.
Самое, что смешное, что оно только там и используется. Хотя возможности для использования данного подхода - огромны.
Для всяческого "собственного маршалинга".
Ну и для ORM например. Хотя есть и другой путь. Несколько обратный:
http://18delphi.blogspot.ru/2013/07/blog-post.html
http://roman.yankovsky.me/?p=740
Я беру описалово данных, скрещиваю со скриптами и получаю моки.
ОтветитьУдалить