Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi generische Callback-Liste erstellen ? (https://www.delphipraxis.net/150442-generische-callback-liste-erstellen.html)

himitsu 16. Apr 2010 19:21


generische Callback-Liste erstellen ?
 
Ich wollte mir eine grundlegende Eventliste erstellen, also eine Liste womit Callbackprozeduren gespeichert werden und auch aufgerufen werden können.

Als "normale" Liste hab ich schon lange im Einsatz und da ich
Delphi-Quellcode:
// Ausschnitt mit den wichtigsten Headern und Funktionen

Type TEvent = Procedure(Sender: TMyObject) of Object;
     TCallback = Class
       FEventList: Array of TEvent;
       Procedure Add  (Const Value: TEvent);
       Procedure Remove(Const Value: TEvent);
       Procedure Call (Sender: TSender);
     End;

Procedure TCallback.Call(Sender: TSender);
  Var i: Integer;

  Begin
    For i := Count - 1 downto 0 do
      FEventList[i](Sender);
  End;
Nun brauch ich grade in einen Projekt mehrere dieser Listen und dachte mir
"och, warum erstellst'e dir nicht einfach ein (generisches) Grundgerüst".
So weit so gut ... die Deklaration funktioniert perfekt, aber das Aufrufen der Funktionen funktioniert einfach nicht.
Delphi-Quellcode:
// meine Deklaration

Type TInternalCallback<TProc> = Class(TList<TProc>)
       Procedure Add  (Const Value: TProc);
       Procedure Remove(Const Value: TProc);
     End;
     TCallback<TProc, TSender> = Class(TInternalCallback<TProc>)
       Procedure Call(Const Sender: TSender);
     End;
     TCallback<TProc, TSender, TParam1> = Class(TInternalCallback<TProc>)
       Procedure Call(Const Sender: TSender; Const Param1: TParam1);
     End;
     TCallback<TProc, TSender, TParam1, TParam2> = Class(TInternalCallback<TProc>)
       Procedure Call(Const Sender: TSender; Const Param1: TParam1; Const Param2: TParam2);
     End;
     ...
Delphi-Quellcode:
// das Ganze etwas übersichtlicher (inkl. Markierung der Fehlerstelle)

Type TCallback<TProc, TSender> = Class(TList<TProc>)
       Procedure Add  (Const Value: TProc);
       Procedure Remove(Const Value: TProc);
       Procedure Call (Sender: TSender);
     End;

Procedure TCallback<TProc, TSender>.Call(Sender: TSender);
  Var i: Integer;

  Begin
    For i := Count - 1 downto 0 do
      Items[i](Sender);
      //      ^ genau hier
  End;
Zitat:

[DCC Fehler] OpenToolsAPI.pas(495): E2066 Operator oder Semikolon fehlt
Sowas bringt natürlich die selbe Fehlermldung:
Delphi-Quellcode:
For i := Count - 1 downto 0 do
  TProc(Items[i])(Sender);
  //      ^ genau hier
Und dieses geht auch nicht
Delphi-Quellcode:
Type TCallback<TProc: Procedure, TSender> = Class(TList<TProc>)
       Procedure Add  (Const Value: TProc);
       Procedure Remove(Const Value: TProc);
       Procedure Call (Sender: TSender);
     End;
Zitat:

[DCC Fehler] OpenToolsAPI.pas(18): E2029 Bezeichner erwartet, aber 'PROCEDURE' gefunden
Und verwenden wollte ich es z.B. so:
(dieses nimmt der Compiler auch kommentarlos entgegen)
Delphi-Quellcode:
Type TEvent = Procedure(Sender: TMyObject) of Object;
  TEventList = TCallback<TEvent, TMyObject>;
Wie kann ich also dem Compiler sagen, daß dieses "TProc" einen Methoden-Zeiger darstellen soll?


[add]
Wenn sich für den Aufruf nichts finden läßt, dann werde ich wohl doch zumindestens die Call-Prozedur ohne Generics lösen und für jede Methoden-Zeiger eine eigene Klasse von dem Basistypen
Delphi-Quellcode:
TInternalCallback<TProc> = Class(TList<TProc>)
ableiten

Stevie 21. Apr 2010 06:57

Re: generische Callback-Liste erstellen ?
 
Delphi-Quellcode:
type
  TInternalCallback<T> = class(TList<T>)
    procedure Add(const Value: T); virtual; abstract;
    procedure Remove(const Value: T); virtual; abstract;
  end;
  TCallback<T> = class(TInternalCallback<TProc<T>>)
    procedure Call(const Sender: T);
  end;

procedure TCallback<T>.Call(const Sender: T);
var
  i: Integer;
begin
  for i := 0 to Count - 1 do
    Items[i](Sender);
end;
Man sollte niemals Typenparameter mit konkreten Typen verwechseln. TProc ist ein in SysUtils definierter Typ.

Alternativ:
Delphi-Quellcode:
type
  TEvent = procedure of object;
  TEvent<T> = procedure(Sender: T) of object;

  TInternalCallback<T> = class(TList<T>)
    procedure Add(const Value: T); virtual; abstract;
    procedure Remove(const Value: T); virtual; abstract;
  end;
  TCallback<T> = class(TInternalCallback<TEvent<T>>)
    procedure Call(const Sender: T);
  end;

procedure TCallback<T>.Call(const Sender: T);
var
  i: Integer;
begin
  for i := 0 to Count - 1 do
    Items[i](Sender);
end;

himitsu 21. Apr 2010 07:32

Re: generische Callback-Liste erstellen ?
 
Das mit dem TProc ist eigentlich kein Problem, da hier das TProc aus der SysUtils lokal mit meinem TProc überschrieben wird,
aber ich nehm mich deinem Vorschlag an und werde es ohne die T's schreiben.
Delphi-Quellcode:
type TCallback<Proc, Sender> = class..
Aber die Idee das TEvent nochmals vorzudeklarieren war eine gute Idee, denn so weiß der Compiler jetzt, daß es ein Methodenzeiger ist. :thumb:
Hatte das Event ja erst nachher deklariert.

Werde das TEvent aber noch mit in den Public-Bereicht des TCallback verschieben. :angel2:
(ich denke mal, daß sollte auch funktionieren)


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:54 Uhr.

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