AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Multicaster in Delphi 2009

Ein Thema von Phoenix · begonnen am 20. Apr 2009 · letzter Beitrag vom 23. Apr 2009
Antwort Antwort
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.639 Beiträge
 
#1

Multicaster in Delphi 2009

  Alt 20. Apr 2009, 23:37
Hi,

ich habe ein Problem mit Delphi 2009.

Ich will einen Multicast delegate für einen TButton-Click bauen (beispielhaft, soll gegen später generisch mit jedem Event gehen).

Die Idee ist folgende:
Mittels eines Class helpers erweitere ich die Klasse TButton um zwei Methoden: AddEvent und RemoveEvent.
In einem generischen Dictionary merke ich mir dann zu jedem verwendeten Button eine Liste mit registrierten Events. Wird mit AddEvent eines hinzugefügt, so hänge ich dieses Event in die Liste ein und bei remove soll das Event auch aus der Liste entfernt werden. (Ja, ich fake mittels des Dictionarys sozusagen ein Property zu dem Button dazu - class helper mit zusätzlichen Properties könnten mittels eines generischen Dictionaries auch so hinzubekommen sein).

Das Hinzufügen und Ausführen der Events funktioniert auch schon, aber das Entfernen eines einmal registrierten Events schmeisst eine Zugriffsverletzung, und zwar genau an der Stelle an dem geprüft wird, ob das Event in der Liste ist.

Kann man jemand drübergucken und mir sagen, warum ich das Event auf diese Art zwar in die Liste hinzufügen, aber nicht mer entfernen kann? Mir erscheint das etwas unlogisch und die Zugriffsverletzung passiert jedes mal an einer anderen Adresse, so dass ich gar nicht sagen kann wo die herkommt.

Hier mal die komplette betreffende Unit:

Delphi-Quellcode:
unit UMulticaster;

interface

uses
  Classes, StdCtrls;

type
   TButtonMulticaster = class helper for TButton
     procedure AddEvent(event: TNotifyEvent); overload;
     procedure RemoveEvent(event: TNotifyEvent); overload;
   end;

implementation

uses
   SysUtils, Generics.Defaults, Generics.Collections;

type
  eventList = TList<TNotifyEvent>;
  eventDictionary = TDictionary<TButton, eventList>;

  EventDispatcher = class
  private
    eventList: eventDictionary;
  public
    constructor Create;
    destructor Destroy;
  public
    procedure OnSomeButtonClick(sender: TObject);
    property Events: eventDictionary read eventList write eventList;
  end;

var
  dispatcher: EventDispatcher;

{ EventDispatcher }

constructor EventDispatcher.Create;
begin
  eventList := eventDictionary.Create();
end;

destructor EventDispatcher.Destroy;
begin
  FreeAndNil(eventList);
end;

procedure EventDispatcher.OnSomeButtonClick(sender: TObject);
var
  event: TNotifyEvent;
begin
  for event in eventList.Items[TButton(sender)] do
  begin
    event(sender);
  end;
end;

{ TButtonMulticaster }

procedure TButtonMulticaster.AddEvent(event: TNotifyEvent);
begin
  if not dispatcher.Events.ContainsKey(self) then
  begin
    dispatcher.Events.Add(self, eventList.Create());
    self.OnClick := dispatcher.OnSomeButtonClick;
  end;

  dispatcher.Events[self].Add(event);
end;

procedure TButtonMulticaster.RemoveEvent(event: TNotifyEvent);
var
  evList: eventList;
begin
  if dispatcher.Events.ContainsKey(self) then
  begin
    evList := dispatcher.Events[self];
    if evList.IndexOf(event) >= 0 then // HIER wird die Zugriffsverletzung ausgelöst
      evList.Remove(event);

    if dispatcher.Events[self].Count = 0 then
    begin
      dispatcher.Events.Remove(self);
      self.OnClick := nil;
    end;
  end;
end;

initialization
begin
  dispatcher := EventDispatcher.Create();
end;

finalization
begin
  FreeAndNil(dispatcher);
end;

end.
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#2

Re: Multicaster in Delphi 2009

  Alt 21. Apr 2009, 07:58
Zitat von Phoenix:
Ich will einen Multicast delegate für einen TButton-Click bauen (beispielhaft, soll gegen später generisch mit jedem Event gehen).
Ich teste es später mal, wäre mein erster Code mit Generics

Soll der Code der die class helper Lösung verwendet, eventuell mit fremdem Code kombiniert werden? Man kann nur einen class helper je Klasse definieren, andere Libraries könnten daher mit eigenem Code kollidieren. Delphi erzeugt afaik dann noch nicht einmal eine Warnung.
Michael Justin
habarisoft.com
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.442 Beiträge
 
Delphi 12 Athens
 
#3

Re: Multicaster in Delphi 2009

  Alt 21. Apr 2009, 08:54
Versuch mal, beim eventList.Create() einen Comparer für TNotifyEvent zu übergeben. Der wird nämlich von IndexOf verwendet.
Uwe Raabe
  Mit Zitat antworten Zitat
Benutzerbild von stoxx
stoxx

Registriert seit: 13. Aug 2003
1.111 Beiträge
 
#4

Re: Multicaster in Delphi 2009

  Alt 21. Apr 2009, 17:17
geh jedes Element der Liste durch und prüfe so auf Gleichheit.
Ich vermute, dass Du das Event beim reinen hinschreiben sogar aufrufst, und das willst Du ja nicht.
so geht es bei meinem Multicaster.

Delphi-Quellcode:
procedure TButtonMulticaster.RemoveEvent(event: TNotifyEvent);
var

...
  evList: eventList;
  for i := (eventList.Count - 1) downto 0 do begin
    ev := eventList.Items[i];

    if (TMethod(ev).Code = TMethod(event).Code ) and
       (TMethod(ev).Data = TMethod(event).Data ) then begin
            eventList.Delete(i);
// exit;
       end; // if
  end; // for

end;
Phantasie ist etwas, was sich manche Leute gar nicht vorstellen können.
  Mit Zitat antworten Zitat
Benutzerbild von ULIK
ULIK

Registriert seit: 25. Sep 2006
Ort: Regensburg
427 Beiträge
 
Delphi 11 Alexandria
 
#5

Re: Multicaster in Delphi 2009

  Alt 21. Apr 2009, 20:57
Zitat von Uwe Raabe:
Versuch mal, beim eventList.Create() einen Comparer für TNotifyEvent zu übergeben. Der wird nämlich von IndexOf verwendet.
Jup, damit geht es.

Grüße,
Uli
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#6

Re: Multicaster in Delphi 2009

  Alt 23. Apr 2009, 11:22
Hier ist ein Artikel (mit Source) zu Multicast-Events von Allen Bauer:

The Oracle at Delphi: Multicast events using generics
http://blogs.embarcadero.com/abauer/2008/08/15/38865

Generics in Delphi scheinen noch etwas verbesserungsbedürftig zu sein.

Der Sourcecode zu diesem Artikel ist auch noch nicht komplett veröffentlicht, und im vorletzten Artikel werden auch einige Risiken angesprochen.
Michael Justin
habarisoft.com
  Mit Zitat antworten Zitat
Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.639 Beiträge
 
#7

Re: Multicaster in Delphi 2009

  Alt 23. Apr 2009, 11:28
Ich hab ihn jetzt am laufen.
Muss noch ein paar Feinheiten anpassen, aber im Prinzip sollte er dann sogar für jedes beliebige Event gehen
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:57 Uhr.
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