Autor Beitrag
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: 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:

ausblenden 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:

ausblenden Delphi-Quelltext
1:
Foo.Action := Button1Click(Sender);					


geht das? Und wenn ja, wie?
DHE
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 37

Win XP, Ubuntu 9.04
Delphi 7 PE; Delphi 2010 Prof (Dank AGS 2009 ;-) )
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 573

WIN XP/2000 & 7Prof (Familie:Win95,Win98)

BeitragVerfasst: So 24.05.09 08:20 
Mir sieht das eher nach einer Funktion aus.
Also die wäre dann z.B. so in etwa:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
function AdditionsErgebnisAlsoSumme(Addiator1,Addiator2:int):int;
begin
//also entweder dem Funktionsnamen den Wert übergeben
AdditionsErgebnisAlsoSumme:=Addiator1+Addiator2;
// oder so:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: So 24.05.09 11:20 
user profile iconDHE hat folgendes geschrieben Zum zitierten Posting springen:
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



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 37

Win XP, Ubuntu 9.04
Delphi 7 PE; Delphi 2010 Prof (Dank AGS 2009 ;-) )
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: So 24.05.09 19:28 
user profile iconFinnO hat folgendes geschrieben Zum zitierten Posting springen:
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:

ausblenden volle Höhe Delphi-Quelltext
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 user profile iconFinnO die Variante nicht will.
FinnO Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: So 24.05.09 19:44 
also momentan habe ich folgendes Konstrukt:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type
  TAction = procedure of object;

  TFoo = class
    public
      Action : TAction;
  end;


Zuweisung:
ausblenden Delphi-Quelltext
1:
Foo.Action := Form1.Close; // es funktionieren aber nur Prozeduren ohne Parameter					

Aufruf:
ausblenden Delphi-Quelltext
1:
Foo.Action;					


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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: So 24.05.09 20:01 
user profile iconFinnO hat folgendes geschrieben Zum zitierten Posting springen:
Da sollten so Dinge wie Showmessage('Hallo Welt');genau so funktionieren wie eben FormX.Close;

Ist diese 'Hallo Welt' konstant, oder soll das tatsächlich als Parameter übergeben werden? Dein Code zum Aufruf lässt keine Parameter zu:

user profile iconFinnO hat folgendes geschrieben Zum zitierten Posting springen:
Aufruf:
ausblenden Delphi-Quelltext
1:
Foo.Action;					

Oder wo soll dda bitte schön das 'Hallo Welt' hin? Erklär doch mal genau, was du machen möchtest, oder gehe auf einzelne Vorschläge von uns ein. Ich denke, davon gibt es jetzt bereits genug.
FinnO Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: 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:

ausblenden Delphi-Quelltext
1:
Foo.Action := Showmessage('Hallo Welt'); // oder 'Hallo Yogu' oder sonstwas					

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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: 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:

ausblenden 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:

ausblenden 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:

ausblenden 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:

ausblenden Delphi-Quelltext
1:
2:
3:
asm
  CALL Action;
end;

Eigentlich ganz einfach, wenn man das Prinzip mal verstanden hat.
ffgorcky
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 573

WIN XP/2000 & 7Prof (Familie:Win95,Win98)

BeitragVerfasst: 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 user profile iconYogu das ja eigentlich auch schon (fast) [in dem hier 6. Posting] vorgeschlagen hat:
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: 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.