Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Interface Methode als Parameter übergeben (https://www.delphipraxis.net/211078-interface-methode-als-parameter-uebergeben.html)

t2000 25. Jul 2022 11:27

Delphi-Version: 11 Alexandria

Interface Methode als Parameter übergeben
 
Hallo,

da ich immer noch nicht zu 100% fit bzgl Interfaces bin, hier eine Frage.

Ich möchte eine Funktion als Parameter übergeben. So wie es sonst geht, funktioniert es leider nicht.
Hier meine Deklarationen:

Delphi-Quellcode:
type
  TMeineFunktion = function( const Param: TJSONObject): TJSONObject;// of object;

  IMeinInterface = interface(IInvokable)
  ['{A...0}']
    function DieFunktion( const Param: TJSONObject): TJSONObject;
  end;
Jetzt möchte ich die Funktion als Parameter übergeben. Grund ist, das ich bestimmt 100 Stellen hbe, bei denen immer wieder das gleiche gemacht wird. Neben einem String ist nur die Interface-Funktion variabel.
Ich will nicht 100 Mal den selben Code schreiben (ca. 20-30 Zeilen).

Delphi-Quellcode:
var
  EinInterfaceObjekt: IMeinInterface;
begin
  // Initialisierungen ...

  Ergebnis := Rechenfunktion( EinString, EinInterfaceObjekt.DieFunktion);

end;
Ich bekomme immer Parameterfehler.

Alternativen:
Delphi-Quellcode:
  @EinInterfaceObjekt.DieFunktion

  Addr(EinInterfaceObjekt.DieFunktion)

  var xx: TMeineFunktion;
  with EinInterfaceObjekt do
    xx := @DieFunktion;
gehen alle nicht.
Geht das grundsätzlich nicht oder habe ich einfach noch keine Ahnung, wie damit umzugehen ist?

Für eine schnelle Hilfe wäre ich sehr dankbar.

VG
Thomas

himitsu 25. Jul 2022 11:37

AW: Interface Methode als Parameter übergeben
 
Du übergibst ein Interface, nicht die Funktion "DieFunktion" an Rechenfunktion.
Delphi-Quellcode:
function Rechenfunktion(Str: stirng; Func: IMeinInterface): string;


In der Funktion weißt du, dass "dieses" Interface die geünschte Funktion implementiert definiert und kannst sie demnach dort aufrufen.

t2000 25. Jul 2022 12:16

AW: Interface Methode als Parameter übergeben
 
Ich habe aber viele unterschiedliche Funktionen im Interface. Alle mit identischen Parametern.
Insgesamt gibt es viele Interfaces und jeweils dort drin einige Funktionen. Der Ablauf innerhalb ist immer gleich (REST Kommunikationsschnittsetlle).
Ich wollte mir das Leben einfacher machen und eine zentrale Routine nutzen, in der der ganze REST-Overhead gemacht wird.
Daher würde ich gerne die auszuführende Funktion übergeben.
Ist das möglich?

Uwe Raabe 25. Jul 2022 12:21

AW: Interface Methode als Parameter übergeben
 
Zitat:

Zitat von himitsu (Beitrag 1509221)
In der Funktion weißt du, dass "dieses" Interface die geünschte Funktion implementiert definiert und kannst sie demnach dort aufrufen.

Das funktioniert nur dann, wenn jedes Mal das gleiche Interface übergeben wird und intern immer dieselbe Funktion davon aufgerufen wird. Im diesem Fall hier klappt das nicht:
Delphi-Quellcode:
  Ergebnis1 := Rechenfunktion( EinString, EinInterfaceObjekt.DieFunktion);

  Ergebnis2 := Rechenfunktion( EinString, EinInterfaceObjekt.DieAndereFunktion);
Das Problem bei diesem Ansatz ist, dass Interface-Methoden anders implementiert sind als die in Klassen. Ein hässlicher Workaround wäre sowas:
Delphi-Quellcode:
type
  TMeineFunktion = reference to function( const Param: TJSONObject): TJSONObject;// of object;
...

function Rechenfunktion( const EinString: string; AFunc: TMeineFunktion): string;

...
  Ergebnis := Rechenfunktion( 'EinString',
    function( const Param: TJSONObject): TJSONObject
    begin
      result := EinInterfaceObjekt.DieFunktion(Param);
    end
    );
Wäre IMeinInterface eine Klasse, würde es so funktionieren:
Delphi-Quellcode:
Ergebnis := Rechenfunktion( 'EinString', EinInterfaceObjekt.DieFunktion);

himitsu 25. Jul 2022 12:38

AW: Interface Methode als Parameter übergeben
 
Man könnte mehrere gleiche, von einem Gemeinsamen abgeleitete, Interfaces erstellen
und jedem Interface je eine Methode der Klasse zuweisen.
https://docwiki.embarcadero.com/RADS...olution_Clause

Dann kann man über die Wahl des Interfaces eine der Methoden (das zugehörige Interface) übergeben.


Wenn das Delphi-Objekte in den Interfaces sind, dann ginge auch noch
Delphi-Quellcode:
Ergebnis := Rechenfunktion(EinString, (EinInterfaceObjekt as TEinObjekt).DieFunktion);

// bzw.
Ergebnis := Rechenfunktion(EinString, @(EinInterfaceObjekt as TEinObjekt).DieFunktion);
Für Interfaces in Delphi wird seit einer Weile ein geheimes Fake-Interface implementiert, worüber man von Interfaces das interne Objekt rausholen kann.

jaenicke 25. Jul 2022 15:10

AW: Interface Methode als Parameter übergeben
 
Mir fehlen noch Details um einen Rat geben zu können. Aktuell verstehe ich noch nicht, wie das ganze aufgebaut ist, bzw. warum es so gebaut ist.

Bei Interfaces gibt es viele Möglichkeiten, sei es mit Vererbung oder QueryInterface zu arbeiten usw., aber für den konkreten Fall hilft das nicht weiter.

Deshalb wäre es hilfreich, wenn du mehr zu der Architektur schreiben könntest, damit wir vielleicht eine andere Lösung finden, statt zu versuchen, deine Lösungsidee irgendwie doch zu realisieren.

freimatz 25. Jul 2022 20:24

AW: Interface Methode als Parameter übergeben
 
Sehe ich auch so.
Dazu noch ein Hinweis: mache statt "TMeineFunktion = function" besser "TMeineFunktion = reference to function". Das ist dann universeller verwendbar. (Mehr dazu hier.)

t2000 26. Jul 2022 11:22

AW: Interface Methode als Parameter übergeben
 
Hier nochmal ein paar Hintergründe dazu.
Ich nutze verschiedene TMS REST-Server. Die Schnittstelle auf der Clientseite ist pro Server eine Unit mit einem Interface, welches Funktionen des REST-Servers zur Verfügung stellt. Diese Funktionen hab ich auf der Serverseite programmiert und wird vom Client aufrufen.

Eine Funktionsschnittstelle als Beispiel (Definition/Deklaration auf Server und Client verfügbar):
Delphi-Quellcode:
  IPubFunc = interface(IInvokable)
    ['{FBA5E9E9-87FC-4501-A10E-757218094BF8}']

    function InstallEvent   ( const Param: TJSONObject) : TJSONObject; // Para: ProducerID, ProducerName, Eventname
    function UninstallEvent ( const Param: TJSONObject) : TJSONObject; // Para: EventID, Force
    function SubscribeEvent ( const Param: TJSONObject) : TJSONObject; // Para: EventID, SubscriberID, Important, Priority, CallbackURL
    function UnsubscribeEvent( const Param: TJSONObject) : TJSONObject; // Para: EventID, SubscriberID
    function CancelSubscriber( const Param: TJSONObject) : TJSONObject; // Para: SubscriberID
    function FireEvent      ( const Param: TJSONObject) : TJSONObject; // Para: EventID, Data
  end;

Am Client habe ich einen XDataClient.
Delphi-Quellcode:
xClient     : TXDataClient; // =TMS-Object
Dieser hat eine Funktionsschnitstelle
Delphi-Quellcode:
var
  xPubFunc : IPubFunc;
begin
  xPubFunc := xClient.Service<IPubFunc>;
Wenn ich nun die unterschiedlichen Funktionen aufrufen möchte habe ich (bei mir) ca. 20 Zeilen Overhead.
Darin befindet sich dieser Aufruf
Delphi-Quellcode:
json := xPubFunc.InstallEvent(jsonPara);
wobei "json" und "jsonpara" jeweils TJSONObject Variablen sind.

Da alle Aufrufe der unterschiedlichen REST-Server und auch der unterschiedlichen Funktionen identisch sind (Errorhandling, Datenkonvertierung, usw), wäre eine einzelne Funktion für alle Aufrufe sehr hilfreich. Dynamisch sind ja nur der JSON-Parameter und das jeweilige Interface mit der entsprechenden Funktion.

Soviel mal zum Hintergrund. Die TMS Sourcen möchte ich natürlich nicht ändern. Das ganze läuft soweit super gut.

Ich werde jetzt mal eure Hinweise durchgehen und das eine oder andere ausprobieren.

Viele Dank schon mal.

Thomas

himitsu 26. Jul 2022 11:40

AW: Interface Methode als Parameter übergeben
 
reference-to funktioniert aber bei Interface-Methoden nicht.

Bei IDispatch/OleVariant ginge etwas, da diese Interfaces Funktionen zum Auflösen von Methoden-Namen besitzen (DispInvoke).

Bei normalen/einfachen Interfaces könntest du noch über die RTTI gehen, also Interface-Zeiger plus Methoden-Index oder -Name zu übergeben und es darüber aufzurufen.

Uwe Raabe 26. Jul 2022 12:01

AW: Interface Methode als Parameter übergeben
 
Ist nur so eine Idee:
Delphi-Quellcode:
type
  TJSONObjectFunc = reference to function( const Param: TJSONObject): TJSONObject;// of object;

type
  TPubFunc = record
    class function InstallEvent(Target: IPubFunc): TJSONObjectFunc; static;
    class function UninstallEvent(Target: IPubFunc): TJSONObjectFunc; static;
    class function SubscribeEvent(Target: IPubFunc): TJSONObjectFunc; static;
    class function UnsubscribeEvent(Target: IPubFunc): TJSONObjectFunc; static;
    class function CancelSubscriber(Target: IPubFunc): TJSONObjectFunc; static;
    class function FireEvent(Target: IPubFunc): TJSONObjectFunc; static;
  end;

implementation

class function TPubFunc.InstallEvent(Target: IPubFunc): TJSONObjectFunc;
begin
  Result := function(const Param: TJSONObject) : TJSONObject
    begin
      Result := Target.InstallEvent(Param);
    end;
end;

{ analog für die anderen Methoden }
Aufruf dann so:
Delphi-Quellcode:

procedure HandlePubFunc(xPubFunc: IPubFunc; AFunc: TJSONObjectFunc);
begin
  ...
  json := AFunc(jsonPara);
  ...
end

var
  xPubFunc : IPubFunc;
begin
  xPubFunc := xClient.Service<IPubFunc>;
  HandlePubFunc(xPubFunc, TPubFunc.InstallEvent(xPubFunc));
  ...

  HandlePubFunc(xPubFunc, TPubFunc.FireEvent(xPubFunc));
  ...
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:44 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz