AGB  ·  Datenschutz  ·  Impressum  







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

Callback-Funktion für TObjectList.Sort

Ein Thema von HJay · begonnen am 15. Jan 2011 · letzter Beitrag vom 16. Jan 2011
Antwort Antwort
HJay

Registriert seit: 7. Dez 2009
172 Beiträge
 
Delphi XE7 Enterprise
 
#1

Callback-Funktion für TObjectList.Sort

  Alt 15. Jan 2011, 16:12
Mir gelingt es nicht, die Callbackfunktion als Teil der Klasse zu definieren, zu der sie jeweils gehört. Wenn ich einfach im implementation-Teil die Callbackfunktion definiere, klappt alles auf Anhieb. Es wäre bei vielen verschiedenen Sortierroutinen für viele verschiedene von TObjectList abgeleitete Klassen ja aber eigentlich wünschenswert, die Compare-Funktionen in die Klasse zu integrieren. Man kann aber keine Methode statt des Prozedur-Pointers angeben.

Wie löst Ihr so etwas? Gibt es eine geradlinige Lösung, auf die ich nicht komme?

Code:
function CompareKey1(Item1, Item2: TMyObject):Integer; // OK

function MyObjectList.CompareKey1(Item1, Item2: TMyObject):Integer; // geht nicht

procedure MyObjectList.MySort;
begin
  Sort(@CompareKey1);
end;

Geändert von HJay (15. Jan 2011 um 16:20 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Deep-Sea
Deep-Sea

Registriert seit: 17. Jan 2007
907 Beiträge
 
Delphi XE2 Professional
 
#2

AW: Callback-Funktion für TObjectList.Sort

  Alt 15. Jan 2011, 16:35
Wenn ich dein Problem richtig verstanden habe, musst du deine Funktion wohl als statische Klassenmethode deklarieren:
Delphi-Quellcode:
MyObjectList = class(...)
  ...
  class function CompareKey1(Item1, Item2: TMyObject): Integer; static;
  ...
end;
Chris
Die Erfahrung ist ein strenger Schulmeister: Sie prüft uns, bevor sie uns lehrt.
  Mit Zitat antworten Zitat
HJay

Registriert seit: 7. Dez 2009
172 Beiträge
 
Delphi XE7 Enterprise
 
#3

AW: Callback-Funktion für TObjectList.Sort

  Alt 15. Jan 2011, 17:42
Code:
class function CompareKey1(Item1, Item2: TObject): Integer; static;

Error: "Field definition not allowed after methods or properties."
Compiliert leider nicht...?!

Ich habe mich inzwischen übrigens so beholfen, dass ich den QuickSort-Algorithmus aus Classes.pas kopiert habe und ihn als neue QuickSortByMethod()-Methode direkt in mein TMyObjectList implementiert habe. Diese Methode nimmt jetzt auch Compare-Methoden an und nicht nur normale Funktionen. Dann habe ich gleich noch eine SortOrder ergänzt, so dass das ganz praktisch ist.

Dennoch, es scheint so zu sein, als ob ausgerechnet eine so wichtige Klasse wie TList nicht vollständig objektorientiert implementiert wurde (zumindest in Delphi 6, das ich verwende). Eigentlich ziemlich seltsam.

Aber vielleicht gibt es ja doch eine Lösung, die ich nicht erkenne...

Frei herumfliegende Funktionen quasi gedanklich einer bestimmten Klasse zuzuordnen, kommt mir wirklich merkwürdig vor. Haben die sich das wirklich so gedacht?
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#4

AW: Callback-Funktion für TObjectList.Sort

  Alt 15. Jan 2011, 19:38
Code:
class function CompareKey1(Item1, Item2: TObject): Integer; static;

Error: "Field definition not allowed after methods or properties."
Compiliert leider nicht...?!
Klingt eher so, als ob du die Methode an der falschen stelle deklariert hättest. Methoden müssen immer nach Feldern stehen.
Richtig:
Delphi-Quellcode:
TFoobar = class
  A,B,C: integer;
  D: string;
  procedure MyMethod;
end;
Falsch:
Delphi-Quellcode:
TFoobar = class
  A,B,C: integer;
  procedure MyMethod;
  D: string;
end;
Falsch:
Delphi-Quellcode:
TFoobar = class
  procedure MyMethod;
  A,B,C: integer;
  D: string;
end;
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#5

AW: Callback-Funktion für TObjectList.Sort

  Alt 15. Jan 2011, 19:57
"Classic"-Compiler mögen diese Deklaration nicht.
Also mit anderen Worten: static ist kein Schlüsselwort, sondern wird als Feldname innerhalb des Objektes interpretiert. Daher die - völlig korrekte - Fehlermeldung!

Es geht aber doch (gerade probiert mit Delphi 5) - mit einem ganz tiefen Griff in die Trickkiste:
Delphi-Quellcode:
type
  TMyObject = class(...)
    ...
  end;

  TMyObjectList = class(TObjectList)
  public
    procedure MySort;
  published
    {class} function CompareKey1(Item1{, Item2}: TMyObject): Integer;
  end;

{class} function TMyObjectList.CompareKey1(Item1{, Item2}: TMyObject): Integer;
begin
  Result:=Mein_Vergleich(TMyObject(self),Item1); //!!!
end;

procedure TMyObjectList.MySort;
begin
  Sort(MethodAddress('CompareKey1'));
end;
Und es funktioniert tatsächlich!

Trick 1:
Beim Aufruf von Sort in der Methode MySort wird lediglich die Methodenadresse übergeben - also wie bei einer herkömmlichen Prozedur/Funktion. Da es sich dabei nur um einen Zeiger handelt, akzeptiert das der Compiler ohne Widerspruch.
Wichtig: Damit die Methodenadresse gefunden werden kann, muss sie als published deklariert werden - ansonsten muss man RTTI-Mechanismen bemühen.

Trick 2:
Da ist es bei CompareKey1 trotz Lüge an den Compiler um eine Methode handelt, gibt es beim Aufruf einen "unsichtbaren" Parameter - nämlich self. Der ist bei herkömmlichen Objektmethoden mit einem Zeiger auf das Objekt belegt - bei Klassenmethoden eben mit der Klasse, in der sich die Methode befindet. Ich "mißbrauche" ihn einfach zur Übergabe des ersten Items. Das geht gut, weil es sich in allen Fällen um Zeiger handelt. Und da ist es völlig egal, was darin enthalten ist.
Thomas Nitzschke

Geändert von Thom (15. Jan 2011 um 20:11 Uhr)
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#6

AW: Callback-Funktion für TObjectList.Sort

  Alt 15. Jan 2011, 20:05
Das ist aber alles andere als schön... dann würd ich lieber eine externe Prozedur verwenden. Man kann ja als Präfix "TMyObjectList_" verwenden, sodass sie fast aussieht wie eine echte Methode.
  Mit Zitat antworten Zitat
Thom

Registriert seit: 19. Mai 2006
570 Beiträge
 
Delphi XE3 Professional
 
#7

AW: Callback-Funktion für TObjectList.Sort

  Alt 15. Jan 2011, 20:26
Das ist aber alles andere als schön... dann würd ich lieber eine externe Prozedur verwenden. Man kann ja als Präfix "TMyObjectList_" verwenden, sodass sie fast aussieht wie eine echte Methode.

Es ging doch um die Frage, ob es prinzipiell möglich ist, Prozeduren und Funktionen in Objekte zu "verlegen". Die eindeutige und kurze Antwort dazu lautet: Ja!
Die Frage war nicht, ob der Quellcode schön aussieht. Programmierer von bösen Tierchen achten wahrscheinlich auch weniger auf "Schönheit", Eleganz und akademische Lehrdoktrinen als mehr auf Funktionalität...

Außerdem: Was stört Dein Schönheitsempfinden? Dass ein Parameter "fehlt"!?
Hast Du Dir schon einmal die Unit ObjAuto angeschaut? Wahrscheinlich nicht - denn dann hättest Du einen Eindruck davon, was "unschön" aussieht und wieviel Arbeit Entwickler dafür investieren, komplizierte Zusammenhänge für Klick-Mich-Zusammen-Hobby-Programmierer so aufzubereiten, damit diese "schönen" Code schreiben können...
Thomas Nitzschke

Geändert von Thom (16. Jan 2011 um 19:03 Uhr)
  Mit Zitat antworten Zitat
HJay

Registriert seit: 7. Dez 2009
172 Beiträge
 
Delphi XE7 Enterprise
 
#8

AW: Callback-Funktion für TObjectList.Sort

  Alt 16. Jan 2011, 17:19
@Thom: Danke für Deine Mühe. Da habe ich wirklich etwas gelernt, auch wenn ich zugeben muss, dass mir das etwas zuviel Getrickse ist. Aber interessant! Und schön kurz!

Wie gesagt, ich habe jetzt eine eigene Sort-Routine geschrieben, die eben ganz "legal" Methoden annimmt. War letztlich der einfachste Weg für mich und schön übersichtlich.

Ich schließe aber daraus, dass es tatsächlich so ist, dass TList es nicht vorsieht, Methoden zu verwenden. Ganz schön dämlich und altmodisch gelöst, oder?
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

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

AW: Callback-Funktion für TObjectList.Sort

  Alt 16. Jan 2011, 17:39
Ganz schön dämlich und altmodisch gelöst, oder?
Altmodisch? Nun ja, unter der aktuellen Delphi XE wird TObjectList eigentlich gar nicht mehr benutzt. Als modernen Ersatz gibt es da eine generische TObjectList<T>, die eben auch typsicher ist. Als Vergleichsvehikel gibt man dort ein IComparer<T> Interface an, für das es die verschiedensten Implementierungen gibt - unter anderem auch eine mit anonymen Methoden. Wirklich altmodisch?

Ach ja, die statische Klassenmethode geht natürlich auch - aber halt noch nicht unter Delphi 6 (ist schließlich auch schon 10 Jahre her)
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  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 07:47 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