| Autor |
Beitrag |
FinnO
      
Beiträge: 1331
Erhaltene Danke: 123
Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
|
Verfasst: Sa 23.05.09 22:49
Hi Leute,
Ist es möglich, einem Objekt eine Prozedur als Eigenschaft zu verpassen? Ich meine dass in etwa so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| type TFoo = class private public Action : Procedure;
end; |
Ziel soll es sein, dass ich dem Foo dann hinterher sowas zuweisen kann:
Delphi-Quelltext 1:
| Foo.Action := Button1Click(Sender); |
geht das? Und wenn ja, wie?
|
|
DHE
      
Beiträge: 37
Win XP, Ubuntu 9.04
Delphi 7 PE; Delphi 2010 Prof (Dank AGS 2009 ;-) )
|
Verfasst: Sa 23.05.09 23:39
Was du suchst nennt sich Methodenzeiger
Schau mal hier nach
oder such nach Methodenzeigern in der Delphi-Dokumentation oder hier im Forum
|
|
ffgorcky
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: So 24.05.09 08:20
Mir sieht das eher nach einer Funktion aus.
Also die wäre dann z.B. so in etwa:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| function AdditionsErgebnisAlsoSumme(Addiator1,Addiator2:int):int; begin AdditionsErgebnisAlsoSumme:=Addiator1+Addiator2; result:=Addiator1+Addiator2; end; |
Ich frage mich immer, welches sauberer ist - gehen tut doch beides -- oder?
Die beiden Parameter könntest Du Dir natürlich auch sparen, wenn Du stattdessen direkt auf Deine Objekt-Werte zugreifst.
Oder habe ich die Frage gerade total verkehrt verstanden?
|
|
FinnO 
      
Beiträge: 1331
Erhaltene Danke: 123
Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
|
Verfasst: So 24.05.09 11:20
DHE hat folgendes geschrieben : | Was du suchst nennt sich Methodenzeiger
Schau mal hier nach
oder such nach Methodenzeigern in der Delphi-Dokumentation oder hier im Forum |
So ich habe das jetzt so zum laufen gebracht. Was mich jetzt ein bisschen stört ist, dass ich nur Methoden aufrufen kann, die genau die Parameter haben, wie ich in meinem Zeiger da festgelegt habe. Kann ich das auch so lösen, dass beliebige Prozeduren aufgerufen werden können?
|
|
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: So 24.05.09 11:50
Ganz so, wie Du das willst, geht es nicht, aber Du könntest Deine Methoden überladen (Stichwort overload).
|
|
DHE
      
Beiträge: 37
Win XP, Ubuntu 9.04
Delphi 7 PE; Delphi 2010 Prof (Dank AGS 2009 ;-) )
|
Verfasst: So 24.05.09 17:28
Statt Methoden zu überladen kannst du auch einfach Interfaces nutzen.
Dann übergibst du der Methode als Parameter einfach eine vom Interface abgeleitete Klasse und
diese implementiert dann einfach die Funktion.
|
|
Yogu
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: So 24.05.09 19:28
FinnO hat folgendes geschrieben : | | Was mich jetzt ein bisschen stört ist, dass ich nur Methoden aufrufen kann, die genau die Parameter haben, wie ich in meinem Zeiger da festgelegt habe. Kann ich das auch so lösen, dass beliebige Prozeduren aufgerufen werden können? |
Wenn du eine Prozedur mit Parametern aufrufst, musst du ja auch irgendwelche Parameter übergeben. Wo legst du diese Werte fest?
Eine Möglichkeit wäre eine Assembler-Anweisung. So habe ich externe Funktionen meiner Script-Eingine gelöst:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
| var ParameterCount, Result, Paramter1, Parameter2, Parameter3: Integer; Pntr: Pointer; begin case ParameterCount of 0: asm CALL Pntr MOV tmp1, EAX end;
1: begin asm MOV EAX, Parameter1 CALL Pntr MOV Result, EAX end; end;
2: begin asm MOV EAX, Parameter1 MOV EDX, Parameter2 CALL Pntr MOV Result, EAX end; end;
3: begin asm MOV EAX, Parameter1 MOV EDX, Parameter2 MOV ECX, Parameter3 CALL Pntr MOV Result, EAX end; end;
4: begin asm MOV EAX, Parameter1 MOV EDX, Parameter2 MOV ECX, Parameter3 PUSH Parameter4 CALL Pntr MOV Result, EAX end; end; end; |
ParameterCount gibt die Anzahl der Parameter an, Pntr ist ein Zeiger auf die Funktion und in der Variable Result ist nachher der Rückgabewert gespeichert. Allerdings musst du selbstverständlich vorher wissen, wie viele Parameter die Funktion hat, denn wie willst du sonst wissen, wie viele Werte auf den Stack geschrieben werden sollen (siehe PUSH).
Ich weiß selbst, dass meine Case-Konstruktion nicht gerade das Optimum ist, und würde mich selbst um eine Verbesserung des Codes freuen. Das soll aber nicht Thema dieses Threads sein, falls FinnO die Variante nicht will.
|
|
FinnO 
      
Beiträge: 1331
Erhaltene Danke: 123
Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
|
Verfasst: So 24.05.09 19:44
also momentan habe ich folgendes Konstrukt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| type TAction = procedure of object;
TFoo = class public Action : TAction; end; |
Zuweisung:
Delphi-Quelltext 1:
| Foo.Action := Form1.Close; |
Aufruf:
Delphi-Quelltext
Mein Wunsch wäre jetzt ja eine Universallösung, in der ich JEDE beliebige Prozedur so zuweisen kann und später wieder aufrufen kann. Wenn das gar nicht klappen sollte, muss ich da wohl eine andere, unbequeme Lösung finden
€: Vielleicht noch zum Verwendungszweck: Ich möchte recht variabel einem Objekt eine Methode zuweisen. Diese Methode soll halbwegs zur Laufzeit zugewiesen werden - ich nehme aus einem Pool an Möglichen Funktionen eben die gewünschte. Da sollten so Dinge wie Showmessage('Hallo Welt');genau so funktionieren wie eben FormX.Close;
|
|
Yogu
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: So 24.05.09 20:01
|
|
FinnO 
      
Beiträge: 1331
Erhaltene Danke: 123
Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
|
Verfasst: So 24.05.09 20:23
Nein die soll nicht als Parameter übergeben werden, sonder das Hallo Welt ist ja Parameter von Showmessage. Jetzt möchte ich erreichen, dass erstens:
Delphi-Quelltext 1:
| Foo.Action := Showmessage('Hallo Welt'); |
funktioniert und, dass ich das ganze dann mitt
Foo.Action auch wieder aufrufen kann.
aber genau so auch noch Foo.Action := Form1.Close oder Foo.Action := Button1OnClick(Sender); Halt etwas beliebiges stehen kann. Einfach eine Prozedur oder Funktion als Eigenschaft in einer Klasse.
|
|
Yogu
      
Beiträge: 2598
Erhaltene Danke: 156
Ubuntu 13.04, Win 7
C# (VS 2013)
|
Verfasst: So 24.05.09 21:17
Ah, jetzt verstehe ich. Das ist gar nicht mal so schwer, wie du es dir vorstellst. Du musst nur ein wenig "umdenken":
Erstelle einfach eine kleine Funktion, die den Aufruf beinhaltet:
Delphi-Quelltext 1: 2: 3: 4:
| procedure SayHelloToTheWorld; begin ShowMessage('Hallo Welt'); end; |
Und diese Funktion kannst du nun ganz einfach für Action verwenden:
Delphi-Quelltext 1:
| Foo.Action := SayHelloToTheWorld; |
Allerdings weiß ich nicht, ob du Klassenmethoden (also zum Beispiel Form1.Close) und normale Prozeduren (z.B. SayHelloToTheWorld) mischen kannst. Für den Fall würde ich einen einfachen Pointer als Typ für Action vorschlagen:
Delphi-Quelltext 1: 2: 3: 4: 5:
| var Action: Pointer; begin Action := @SayHelloToTheWorld; Action := @Form1.Close; end; |
Und diese Prozedur rufst du wie folgt auf:
Delphi-Quelltext 1: 2: 3:
| asm CALL Action; end; |
Eigentlich ganz einfach, wenn man das Prinzip mal verstanden hat.
|
|
ffgorcky
      
Beiträge: 573
WIN XP/2000 & 7Prof (Familie:Win95,Win98)
|
Verfasst: So 24.05.09 21:23
Das würde ich dann eher so machen, dass man da einen Integer-Wert nimmt, der dann genau festlegt, welche Prozedur im Moment aufgerufen werden soll - also so wie Yogu das ja eigentlich auch schon (fast) [in dem hier 6. Posting] vorgeschlagen hat:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| case welcheProzedur of 0:macheDieseProzedur(); 1:macheJeneProzedur(); 2:macheEineAndereProzedur(); 3:macheNochEineAndereProzedur(); 4:macheKeineAhnungMehrWas(); end; |
Aber ich würde daraus wirklich voneinander unabhängige Prozeduren machen und da ganze nicht einfach nur mit begin und end in die case-Abfrage reinbauen. Das sieht ja bei Dir etwas umfassender aus!
Zuletzt bearbeitet von ffgorcky am So 24.05.09 21:31, insgesamt 1-mal bearbeitet
|
|
FinnO 
      
Beiträge: 1331
Erhaltene Danke: 123
Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
|
Verfasst: So 24.05.09 21:29
@Yogu
hmm okay, diesen(s?) Workaround benutze ich auch gerade, fand ihn aber irgendwie unsauber. Aber wenns nicht anders geht dann... mein Gott mach ichs eben so  kann als gelöst betrachtet werden.
|
|
|