AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials Delphi for...in...do für eine existierende Klasse erstellen
Tutorial durchsuchen
Ansicht
Themen-Optionen

for...in...do für eine existierende Klasse erstellen

Ein Tutorial von sakura · begonnen am 22. Apr 2005 · letzter Beitrag vom 22. Apr 2005
Antwort Antwort
Benutzerbild von sakura
sakura
Registriert seit: 10. Jun 2002
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.

......

Änderung: Delphi Win32 unterstützt class helpers, die Hilfe sagt die sind nur für Delphi.NET. Sample entsprechend angepasst.
Angehängte Dateien
Dateityp: pas ulanguagesex_330.pas (1,0 KB, 18x aufgerufen)
Ich bin nicht zurück, ich tue nur so
 
Benutzerbild von Sharky
Sharky

 
Delphi 2006 Professional
 
#2
  Alt 22. Apr 2005, 14:52
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?
Stephan B.
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#3
  Alt 22. Apr 2005, 14:56
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

......
Daniel W.
  Mit Zitat antworten Zitat
tommie-lie
 
#4
  Alt 22. Apr 2005, 15:58
Ich weiß nicht, wie das in Delphi.NET gehandhabt wird (sowas fasse ich nicht an ), 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?
Mir fehlt die Syntax dafür, von Delphi/Win32 ausgehend etwas wie TLanguagesEnum = class(IEnumerator) Edit: System.Collections in dem Fall natürlich nicht vergessen
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#5
  Alt 22. Apr 2005, 16:04
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.

......
Daniel W.
  Mit Zitat antworten Zitat
tommie-lie
 
#6
  Alt 22. Apr 2005, 16:07
Da gibt's schon extra verschiedene Icons dafür und dann sowas...
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#7
  Alt 22. Apr 2005, 17:09
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

......
Daniel W.
  Mit Zitat antworten Zitat
Robert_G
 
#8
  Alt 22. Apr 2005, 17:10
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 )

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.
  Mit Zitat antworten Zitat
Benutzerbild von maximov
maximov

 
Delphi 2005 Professional
 
#9
  Alt 22. Apr 2005, 17:16
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 )
...
Moin Robert,

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

grüsse.
  Mit Zitat antworten Zitat
Robert_G
 
#10
  Alt 22. Apr 2005, 17:23
Ich kann dir ja mal meine Version deines dpCollection templates schicken.
Du kannst sie dann korrekturlesen, veröffentlichen, verbieten, whatever...


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 )
  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 05:21 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