![]() |
AW: Speicherleck bei der Verwendung von anonymen Methoden
Zitat:
Das kann man testen, indem man einfach das hier schreibt
Delphi-Quellcode:
Weiterhin kann man über RTTI auf das Object, was dahinter steckt, zugreifen (siehe
type
TProcObject = class(TInterfacedObject, TProc) public procedure Invoke; end; ![]() Vergleichen und in einer Liste speichern müsste somit auch kein Problem sein. Man kann auch andersrum eine anonyme Methode an ein Event hängen (man muss sich nur klar machen, dass ein Event kein managed type ist, dementsprechend muss man sich da dann selber drum kümmern) Wie das geht, hat Barry ![]() Mit diesem Wissen kann man eigentlich fast alles mit einer anonymen Methode machen. |
AW: Speicherleck bei der Verwendung von anonymen Methoden
Delphi-Quellcode:
Du kannst UnregisterCallback so oft aufrufen, wie du willst.
unit Unit1;
interface uses SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Generics.Defaults, Generics.Collections, StdCtrls; type TCallback = TProc<TObject>; TForm1 = class(TForm) RegisterButton: TButton; UnregisterButton: TButton; CallButton: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure RegisterButtonClick(Sender: TObject); procedure UnregisterButtonClick(Sender: TObject); procedure CallButtonClick(Sender: TObject); procedure MyCallback(Sender: TObject); private FList: TList<TCallback>; procedure RegisterCallback(CB: TCallback); procedure UnregisterCallback(CB: TCallback); procedure DoCallbacks(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin FList := TList<TCallback>.Create; end; procedure TForm1.FormDestroy(Sender: TObject); begin FList.Free; end; procedure TForm1.RegisterButtonClick(Sender: TObject); begin RegisterCallback(MyCallback); end; procedure TForm1.UnregisterButtonClick(Sender: TObject); begin UnregisterCallback(MyCallback); end; procedure TForm1.CallButtonClick(Sender: TObject); begin DoCallbacks(Self); end; procedure TForm1.MyCallback(Sender: TObject); begin ShowMessage('Hallo'); end; procedure TForm1.RegisterCallback(CB: TCallback); begin if FList.IndexOf(CB) < 0 then FList.Add(CB); end; procedure TForm1.UnregisterCallback(CB: TCallback); begin //if FList.IndexOf(CB) >= 0 then // ShowMessage('ist drin'); FList.Remove(CB); end; procedure TForm1.DoCallbacks(Sender: TObject); var i: Integer; begin for i := FList.Count - 1 downto 0 do FList[i](Sender); end; end. Bei jedem Aufruf wird ein neues Interface aus Callback erstellt. Also kann dieser Callback nicht mehr in der Liste gefunden werden. Aber danke für den Link, womöglich läßt sich das ja im einer schönen Vergleichsfunktion verbauen. :) |
AW: Speicherleck bei der Verwendung von anonymen Methoden
Zitat:
In dieser Hinsicht haben wir also ![]() |
AW: Speicherleck bei der Verwendung von anonymen Methoden
:cry:
Tja, wäre die Interfacedeklration öffentlich, und hätte Emba entsprechende (Vergleichs)Methoden verbaut, oder hätte man den Vergleichsoperator entsprechend ausgelegt, dann gäbe es das Problem nicht. |
AW: Speicherleck bei der Verwendung von anonymen Methoden
Zitat:
Ich werd mal Barry fragen, ob es eine Möglichkeit gibt, diese herauszufinden. Das ist atm das Wissen, was mit noch fehlt, um eine Vergleichsroutine zu bauen. |
AW: Speicherleck bei der Verwendung von anonymen Methoden
Antwort von Barry:
Zitat:
|
AW: Speicherleck bei der Verwendung von anonymen Methoden
Zitat:
|
AW: Speicherleck bei der Verwendung von anonymen Methoden
Wenn du
Delphi-Quellcode:
über die Definition der anonymen Methode schreibst, bekommst du RTTI für diesen Typ. Wie ja schon gesagt, sind anonyme Methoden nix anderes als Interfaces.
{$M+}
Mit folgender Routine kannst du dir die Signatur der Invoke Methode und die Felder für die captured Variablen ausgeben lassen:
Delphi-Quellcode:
Bedenke dabei, dass im Falle von mehreren Anonymen Methoden im gleichen Scope nur 1 Objekt erzeugt wird.
procedure ListProcedureRefRtti(var MethodRef;
const TypeInfo: Pointer; const Lines: TStrings); var i: IInterface absolute MethodRef; o: TObject; c: TRttiContext; t: TRttiType; f: TRttiField; m: TRttiMethod; begin o := i as TObject; t := c.GetType(TypeInfo); Lines.Add('Interface: ' + t.ToString); Lines.Add('Method:'); for m in t.GetMethods do begin if m.Parent = t then Lines.Add(m.ToString); end; t := c.GetType(o.ClassInfo); Lines.Add('Object: ' + t.ToString); Lines.Add('Fields:'); for f in t.GetFields do begin if f.Parent = t then Lines.Add(f.ToString); end; end; Daher hast du bei folgendem Aufruf jedesmal Self und i als Felder. Ich habe hierzu TProc und TFunc lokal redefiniert und ihnen das
Delphi-Quellcode:
verpasst. Ich hatte Barry auch schon vor einiger Zeit darauf angesprochen das eventuell mal in die SysUtils Definitionen aufzunehmen:
{$M+}
Delphi-Quellcode:
var
p: TProc; f: TFunc<Integer, Boolean>; i: Integer; begin Memo1.Clear; p := procedure begin ShowMessage(Caption) end; ListProcedureRefRtti(p, TypeInfo(TProc), Memo1.Lines); f := function(Arg: Integer): Boolean begin Result := Arg mod 2 = 0 end; ListProcedureRefRtti(f, TypeInfo(TFunc<Integer, Boolean>), Memo1.Lines); p := procedure begin ShowMessage(IntToStr(i)) end; ListProcedureRefRtti(p, TypeInfo(TProc), Memo1.Lines); |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:26 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