Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I cast an object as an interface which is a generic type constraint in Delphi

I need to interact with series of .Net web services. There are currently about 150. Since delphi 2010 uses Thttprio to achieve this, I am trying to create a generic Proxy on the client side that can be called to create the appropriate soap service client. Does anyone have any idea how I can cast the httprio object to a generic interface type?

Thanks

Below is the proxy function I'm trying to use:

class function Web.Proxy<T>(svc: string): T;
var
  HTTPRIO : THTTPRIO;
begin
  HTTPRIO := THTTPRIO.Create(nil);
  HTTPRIO.URL := GetServiceURL(svc);
  Result:= HTTPRIO as T; //<-- Fails with "operator not applicable to this operand type"
  // Result:= T(HTTPRIO); //<-- also fails, but with "invalid typecast"
end;

The idea is that I can call this with:

Web.Proxy<AutmobileServiceSoap>('svc.asmx').GetAutomobile(125);

The WSDL import has the AutmobileServiceSoap defined as follows:

AutmobileServiceSoap = interface(IInvokable)

And all the wsdl imports have a function that returns the httprio object cast in a similar manner:

function GetAutomobileServiceSoap(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): AutomobileServiceSoap;
const
  defWSDL = 'http://localhost:8732/Cars.Server/Data/AutomobileService.asmx?WSDL';
  defURL  = 'http://localhost:8732/Cars.Server/Data/AutomobileService.asmx';
  defSvc  = 'AutomobileService';
  defPrt  = 'AutomobileServiceSoap12';
var
  RIO: THTTPRIO;
begin
  Result := nil;
  if (Addr = '') then
  begin
    if UseWSDL then
      Addr := defWSDL
    else
      Addr := defURL;
  end;
  if HTTPRIO = nil then
    RIO := THTTPRIO.Create(nil)
  else
    RIO := HTTPRIO;
  try
    Result := (RIO as AutomobileServiceSoap);
    if UseWSDL then
    begin
      RIO.WSDLLocation := Addr;
      RIO.Service := defSvc;
      RIO.Port := defPrt;
    end else
      RIO.URL := Addr;
  finally
    if (Result = nil) and (HTTPRIO = nil) then
      RIO.Free;
  end;
end;
like image 693
reckface Avatar asked Mar 23 '23 08:03

reckface


1 Answers

You have to use RTTI to get the GUID of the interface

type
  Web = class
    class function Proxy<T: IInterface>(svc: string): T;
  end;

class function Web.Proxy<T>(svc: string): T;
var
  HTTPRIO: THTTPRIO;
  data: PTypeData;
begin
  HTTPRIO := THTTPRIO.Create(nil);
  HTTPRIO.URL := GetServiceURL(svc);
  data := GetTypeData(TypeInfo(T));
  if ifHasGuid in data.IntfFlags then
  begin
    HTTPRIO.QueryInterface(data.Guid, Result);
  end;
end;

If you specify the IInterface constraint you can be sure that T is always an interface (otherwise you have to check the TypeKind of the TypeInfo also).

like image 51
Stefan Glienke Avatar answered Apr 13 '23 22:04

Stefan Glienke