![]() |
Aufrufen einer Unterprozedur mit AsyncCalls
Ich habe eine Prozedur mit Unterprozeduren:
Delphi-Quellcode:
So, wie es da oben steht, funktioniert das natürlich nicht. In Wirklichkeit ist TuWas bei mir eine Klassenmethode von TForm1, und das funktioniert ohne Probleme. Ich hätte es aber aus rein codeökonomischen Gründen gern in einer Unterfunktion. Ich habe auch eine Ahnung, wie man das machen könnte, insbesondere von
procedure TForm1.Haupt;
var i:integer; //------------------------------------------------------- function TuWas(i:integer):integer; begin end; //------------------------------------------------------- procedure RufeAuf; begin TAsyncCalls.Invoke( procedure var i:integer; begin For i := 0 to 10 do If i < 11 then TAsyncCalls.Invoke<integer>(TuWas,i)); end); end; //------------------------------------------------------- begin RufeAuf; end; ![]() |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Was erwartet Invoke denn als Argument? Daran kann man sehen was geht und was nicht
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Delphi-Quellcode:
class function Invoke<T>(Event: TAsyncCallArgGenericMethod<T>; const Arg: T): IAsyncCall; overload; static;
IAsyncCall = interface { Sync() waits until the asynchronous call has finished and returns the result value of the called function if that exists. } function Sync: Integer; { Finished() returns True if the asynchronous call has finished. } function Finished: Boolean; { ReturnValue() returns the result of the asynchronous call. It raises an exception if called before the function has finished. } function ReturnValue: Integer; { ForceDifferentThread() tells AsyncCalls that the assigned function must not be executed in the current thread. } procedure ForceDifferentThread; { added by Zarko Gajic to support canceling tasks waiting in the ThreadPool queue} procedure Cancel; end; TAsyncCallArgGenericMethod<T> = function(Arg: T): Integer of object; |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Jo, dann gehen da nur Methoden rein - ob der Typ wohl deswegen
Delphi-Quellcode:
(bemerke Method) heißt? :stupid:
TAsyncCallArgGenericMethod
Wenn du das ändern möchtest dann einfach
Delphi-Quellcode:
dann geht da alles rein.
// TAsyncCallArgGenericMethod<T> = function(Arg: T): Integer of object;
TAsyncCallArgGenericMethod<T> = reference to function(Arg: T): Integer; (Den Namen muss man nicht ändern, sollte man aber) |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Da
Delphi-Quellcode:
als overload deklariert ist, gibt es doch sicher noch andere Möglichkeiten, oder?
Invoke
Z.B. diese
Delphi-Quellcode:
TAsyncCallArgGenericProc<T> = function(Arg: T): Integer; class function Invoke<T>(Proc: TAsyncCallArgGenericProc<T>; const Arg: T): IAsyncCall; overload; static; Das wäre dann die mit der globalen Function, wobei ich dann aber die Object Method vorziehen würde. Leider gibt es aber keine mit
Delphi-Quellcode:
, weswegen der Ansatz aus dem SO Link nicht zieht.
reference to
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Dann kann man die ja als overload noch hinzufügen :wink:
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Da wollte ich auf Sir Rufo antworten:
"Sind anonyme Methoden nicht auch Methoden? Ich erinnere mich an Lösungen á la
Delphi-Quellcode:
."
M:TMethod
... aber da waren mir die Ereignisse schon voraus. Also OK, ich haue
Delphi-Quellcode:
rein, und dann???
TAsyncCallArgGenericMethod<T> = reference to function(Arg: T): Integer;
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Dann kannst du Methoden, Proceduren und anonyme Methoden übergeben.
Delphi-Quellcode:
deckt alle drei Fälle ab.
reference to
Delphi-Quellcode:
Jetzt klar?
TFooMethod = procedure of object; // NUR Methoden
TFooProc = procedure; // NUR Prozeduren TFooAnon= reference to procedure; // Methoden, Prozeduren, Anonyme Methoden |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Zitat:
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Zitat:
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Zitat:
Ich habe mal Folgendes probiert:
Delphi-Quellcode:
Der Compiler meint "Es gibt keine überladene Version usw....")
procedure TForm1.Haupt;
type TTuWas = reference to function(i:integer):integer; var TuWas:TTuWas ; //------------------------------------------------------- procedure RufeAuf; begin TAsyncCalls.Invoke( procedure var i:integer; begin For i := 0 to 10 do If i < 11 then TAsyncCalls.Invoke<integer>(TuWas,i)); end); end; //------------------------------------------------------- begin RufeAuf; end; Abgesehen davon, dass TuWas ja noch fehlt, schreit er jetzt schon. Das ist es ja, wie geht sowas? |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Weil der Typ nicht passt.
Delphi-Quellcode:
var
TuWas: TAsyncCallArgGenericMethod<Integer>; |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Liste der Anhänge anzeigen (Anzahl: 1)
Oh je, wenn mal Uwe nicht Recht behält...
Sir Rufos Vorschlag wird auch nicht gnädig behandelt, da die Deklaration private ist... Ich hänge die Datei mal an. |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Wenn man keine Rücksicht auf Abwärtskompatibilität legen muss, dann kann man alles in eine normale anonyme Methode packen:
Delphi-Quellcode:
Man kann sich also das gesamte Interface-Implementierungs-Boilerplate-Geraffel komplett sparen und alles euf einen gemeinsamen Typen herunterbrechen.
TAnonWrapper = class
class function Wrap<T>( AProc: TProc<T>; Arg: T ) : TProc; class function Wrap<T,TResult>( AFunc: TFunc<T,TResult>; Arg: T ) : TFunc<TResult>; // das kann man jetzt mit beliebig vielen Argumenten weiterspinnen end; class function TAnonWrapper.Wrap<T>( AProc: TProc<T>; Arg: T ) : TProc; begin Result := procedure () begin AProc( Arg ); end; end; class function TAnonWrapper.Wrap<T,TResult>( AFunc: TFunc<T,TResult>; Arg: T ) : TFunc<TResult>; begin Result := function(): TResult begin Result := AFunc( Arg ); end; end; Und wenn ich nur noch eins implementieren muss, dann ist das halt weniger. |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
So leid es mir tut, beim Anblicken des Codes habe ich eine Ahnung, mehr aber auch nicht.
Wie gesagt, ich habe ja funktionierenden Code, ich möchte nur begreifen, wie man das geschilderte Problem löst. Also ganz schlicht, der Teil
Delphi-Quellcode:
sähe dann wie aus?
//-------------------------------------------------------
procedure RufeAuf; begin TAsyncCalls.Invoke( procedure var i:integer; begin For i := 0 to 10 do If i < 11 then TAsyncCalls.Invoke<integer>(TuWas,i)); end); end; //------------------------------------------------------- Da wir schon beim Lernen sind, den Vorschlag
Delphi-Quellcode:
konnte ich nicht umsetzen da es mir nicht gelang, TAsyncCallArgGenericMethod sichtbar zu machen. Ich habe die Deklaration in AsyncCalls public gemacht, das hat den Compiler leider nicht interessiert.
var
TuWas: TAsyncCallArgGenericMethod<Integer>; Und wie sähe denn dann die Lösung aus? Vielen Dank. |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Wie vielleicht der eine oder andere mitbekommen hat, habe ich die Frage noch einmal auf
![]() Von der Diskussion hier habe ich zwei Dinge mitgenommen:
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Nachdem ich mich ziemlich in das Problem verbissen habe, möchte ich hier eine Lösung präsentieren. Nochmal zu Erinnerung, hier geht es nicht um die Lösung eines konkreten Problems, da eine solche bereits vorliegt. Hier geht es um das Verstehen von Strukturen.
Ausgangspunkt war der apodiktische Verweis von David Heffernan auf die Dokumentation, die klar aussagt: "Nested procedures and functions (routines declared within other routines) cannot be used as procedural values." Demgegenüber steht die Erfahrung, dass viele Dinge möglich sind, auch wenn die Dokumentation (und David Heffernan) etwas anderes sagen. Ich hatte einfach folgende (laienhafte) Vorstellung:
Erhellend (und zunächst enttäuschend) war ![]() Aber dann gibt es noch ![]()
Delphi-Quellcode:
):
reference to
Delphi-Quellcode:
Dieser Code funktioniert, sogar mit der Helper-Klasse von Garco Zajik. Jetzt ist p nicht direkt eine prozedurale Variable, ist aber eigentlich wurscht, die Frage war ja, ob die Klassenmethode in eine Unterprozedur verlagert werden kann. Wie es aussieht, geht das doch. Was sagen die Experten?
procedure TForm1.Haupt;
var i:integer; //------------------------------------------------------- function TuWas(i:integer):integer; begin end; //------------------------------------------------------- procedure RufeAuf; var p:Pointer; begin p := @TuWas; TAsyncCalls.Invoke( procedure var i:integer; begin For i := 0 to 10 do If i < 11 then AsyncHelper.AddTask(TAsyncCalls.Invoke<integer>(p,i)); end); end; //------------------------------------------------------- begin RufeAuf; end; |
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Zitat:
|
AW: Aufrufen einer Unterprozedur mit AsyncCalls
Ja, das ist richtig, auch funktioniert es nicht unter 64 Bit. Zudem gibt es noch weitere Einschränkungen, in bestimmten Fällen muss man globale Variablen benutzen (wegen der Stack-Problematik?).
Fazit also: Lohnt sich nicht. Trotzdem gut, dass die liebe Seele jetzt Ruh hat. Und interessant war's auch. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:40 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