Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Tutorials und Kurse (https://www.delphipraxis.net/36-tutorials-und-kurse/)
-   -   Delphi for...in...do für eine existierende Klasse erstellen (https://www.delphipraxis.net/44661-do-fuer-eine-existierende-klasse-erstellen.html)

sakura 22. Apr 2005 12:42


for...in...do für eine existierende Klasse erstellen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,

in diesem Tutorial möchte ich Euch zeigen, wie man in Delphi 2005 eine Klasse mit der Möglichkeit ausrüstet um das Konstrukt for ... in ... do zu unterstützen. Ähnliches habe ich Euch bereits für COM Collectionen gezeigt.

Nehmen wir als Beispiel die einfache Klasse Delphi-Referenz durchsuchenTLanguages aus der Unit SysUtils heran. Diese Klasse unterstützt das neue Loop-Konstrukt aus Delphi leider nicht. Um alle unterstützten Sprachen zu ermitteln muss man normalerweise folgendes nutzen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Sprache: TLanguages;
  I: Integer;
begin
  Memo1.Clear;
  Sprache := TLanguages.Create;
  try
    for I := 0 to Pred(Sprache.Count) do
      Memo1.Lines.Add(Sprache.Name[I]);
  finally
    Sprache.Free;
  end;
end;
Dieses Konstrukt ist zwar korrent, aber es wäre ja doch schön for...in...do zu nutzen. Damit eine Klasse Ihre einzelnen Elemente in einer for...in...do Schleife zurückliefern kann, muss diese die Methode GetEnumerator zur Verfügung stellen. Die Methode muss eine neue Objekt erstellen, welches dann das Objekt mit den zu enumerierenden Elementen durchläuft und die Elemente einzeln zurückliefert.

In der Delphi 2005 Hilfe: ms-help://borland.bds3/bds3guide/html/DeclarationsAndStatements.htm

Wollen wir dieses also für die Klasse TLanguages tun. Damit wir nicht die RTL von Delphi neu kompilieren müssen, werden wir eine neue Unit erstellen, welche eine Delphi-Referenz durchsuchenHelper Class für TLanguages bietet und für diese den Enumerator zur Verfügung stellt. Das Interface ist recht einfach:
Delphi-Quellcode:
type
  TLanguagesEnum = class
  private
    FIndex: Integer;
    FLanguages: TLanguages;
  public
    constructor Create(aLanguages: TLanguages);
    function GetCurrent: String;
    function MoveNext: Boolean;
    property Current: String read GetCurrent;
  end;

  TLanguagesEx = class helper for TLanguages
  public
    function GetEnumerator: TLanguagesEnum;
  end;
TLanguagesEnum bietet eigentlich nur zwei Methoden. GetCurrent liefert das aktuelle Item (also die Sprache) zurück und MoveNext wählt das nächste Item aus. MoveNext liefert True zurück, wenn ein weiteres Item ausgewählt werden konnte, ansonsten False.

Die Implementierung ist denkbar einfach:
Delphi-Quellcode:
{ TLanguagesEnum }

constructor TLanguagesEnum.Create(aLanguages: TLanguages);
begin
  inherited Create;
  FLanguages := aLanguages;
  FIndex := -1;
end;

function TLanguagesEnum.MoveNext: Boolean;
begin
  Result := FIndex < Pred(Languages.Count);
  if Result then
    Inc(FIndex);
end;

function TLanguagesEnum.GetCurrent: String;
begin
  Result := Languages.Name[FIndex];
end;

{ TLanguagesEx }

function TLanguagesEx.GetEnumerator: TLanguagesEnum;
begin
  Result := TLanguagesEnum.Create(Self);
end;
Jetzt können wir unsere Methode zum Auslesen der Sprachen wie folgend umstellen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Sprache: TLanguages;
  Lang: String;
begin
  Memo1.Clear;
  Sprache := TLanguages.Create;
  try
    for Lang in Sprache do
    begin
      Memo1.Lines.Add(Lang);
    end;
  finally
    Sprache.Free;
  end;
end;
Klar, für dieses Beispiel mag der Aufwand etwas übertrieben sein, allerdings ist das Beispiel sehr einfach zu verstehen, ausserdem wollte Flosse wissen wie das nun eigentlich geht.

Im Anhang ist die ganze Lösung als Download.

...:cat:...

Änderung: Delphi Win32 unterstützt class helpers, die Hilfe sagt die sind nur für Delphi.NET. Sample entsprechend angepasst.

Sharky 22. Apr 2005 14:52

Re: for...in...do für eine existierende Klasse erstellen
 
Hai Felli *g*

danke für die schöne Erklärung.

Sehe ich das jetzt richtig das es pro Klasse nur eine Eigenschaft geben kann die über einen Enumerator angesprochen werden kann?

Im Falle von TLanguages könnte ich also nicht sowohl .Name als auch .ID verwenden?

sakura 22. Apr 2005 14:56

Re: for...in...do für eine existierende Klasse erstellen
 
Zitat:

Zitat von Sharky
Sehe ich das jetzt richtig das es pro Klasse nur eine Eigenschaft geben kann die über einen Enumerator angesprochen werden kann?

Das siehst Du korrekt :-) Aber im allgemeinen sollte das auch ausreichen, schließlich kann der Enumerator auch Klassen und Records zurückgeben ;-)

...:cat:...

tommie-lie 22. Apr 2005 15:58

Re: for...in...do für eine existierende Klasse erstellen
 
Ich weiß nicht, wie das in Delphi.NET gehandhabt wird (sowas fasse ich nicht an :mrgreen:), aber wäre es nicht besserer Coding Style, wenn man die Enumerator-Klasse auch explizit als Implementierung von IEnumerator ausweist und die enumerierbare Klasse entsprechend als Implementierung von IEnumerable? :stupid:
Mir fehlt die Syntax dafür, von Delphi/Win32 ausgehend etwas wie
Delphi-Quellcode:
TLanguagesEnum = class(IEnumerator)
Edit: System.Collections in dem Fall natürlich nicht vergessen :zwinker:

sakura 22. Apr 2005 16:04

Re: for...in...do für eine existierende Klasse erstellen
 
Oben haben wir aber eine Win32-Lösung, keine .NET Lösung und da kannst Du für den Enumerator keine Interfaces nutzen, sondern Du musst eine Klasse nutzen.

...:cat:...

tommie-lie 22. Apr 2005 16:07

Re: for...in...do für eine existierende Klasse erstellen
 
:wall: Da gibt's schon extra verschiedene Icons dafür und dann sowas... :roll:

sakura 22. Apr 2005 17:09

Re: for...in...do für eine existierende Klasse erstellen
 
An alle, die sich das schon gesaugt haben, holt Euch die neue Version. Ich habe gerade gelernt, dass class helpers auch für Delphi Win32 zur Verfügung stehen, obwohl die Hilfe anderes sagt. Damit ist die neue Lösung natürlich viel eleganter und leichter zu handhaben :firejump:

...:cat:...

Robert_G 22. Apr 2005 17:10

Re: for...in...do für eine existierende Klasse erstellen
 
Zitat:

Zitat von sakura
Oben haben wir aber eine Win32-Lösung, keine .NET Lösung und da kannst Du für den Enumerator keine Interfaces nutzen, sondern Du musst eine Klasse nutzen.

Richtig. D2005 erwartet eine Klasse und wird die Instanz auch alleine wieder aufräumen. ;)

Für D7 nutze ich in meinen "Templates" ein GetIEnumerator, das GetEnumerator ist erst mit erfülltem {$IFDEF COMPILER9_UP} sichtbar. ;) (Ich will mich ja unter D7 nicht vertippen und ein MemLeak riskieren :shock: )

Da ich ein Anhänger von Listen bin ist sowas auch unter D7 eine Erleichterung. ;)
Delphi-Quellcode:
with SomeCollection.GetIEnumerator() do
  while MoveNext() do
  begin
    Current.Member := SomeValue;
  end;
Auf die Art kann sich dann der Enum durch die interne Liste hangeln ohne, dass ich damit genervt werde. :)

maximov 22. Apr 2005 17:16

Re: for...in...do für eine existierende Klasse erstellen
 
Zitat:

Zitat von Robert_G
...
Für D7 nutze ich in meinen "Templates" ein GetIEnumerator, das GetEnumerator ist erst mit erfülltem {$IFDEF COMPILER9_UP} sichtbar. ;) (Ich will mich ja unter D7 nicht vertippen und ein MemLeak riskieren :shock: )
...
:)

Moin Robert,

hast du deine "Templates" irgendwo veröffentlicht? Oder is das verschluß sache? ...wär doch toll wenn wir auch was davon haben :-D

grüsse.

Robert_G 22. Apr 2005 17:23

Re: for...in...do für eine existierende Klasse erstellen
 
Ich kann dir ja mal meine Version deines dpCollection templates schicken. ;)
Du kannst sie dann korrekturlesen, veröffentlichen, verbieten, whatever... :mrgreen:


Meine listenbasierte Collection ist noch nicht hübsch genug und der Serializer gefällt mir noch überhaupt nicht :? .
(Ich komme leider nicht allzu oft dazu mit Delphi rumzuspielen :( )


Alle Zeitangaben in WEZ +1. Es ist jetzt 14: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