![]() |
for...in...do für COM Collections
Delphi 2005 gibt uns endlich das for...in...do Konstrukt, um über Listen auf einfache Art und Weise zu iterieren. Leider unterstützt es aber keine COM Kollektionen vo Typ IEnumVariant. Mit diesem Tutorial möchte ich Euch eine kleine Einleitung in dieses Thema geben und wie man dieses Konstrukt in eigenen Objekten unterstützen kann.
Hinweis Dieses Tutorial gilt nur für die Delphi Win32 Personalität, nicht für die Delphi.NET Personalität von Delphi 2005. Eine kurze Einführung in das Thema for...in...do hat Danny Thorpe in ![]() ![]() |
Re: for...in...do für COM Collections
COM Enumerationen werden nicht unterstützt, was nun? Leider unterstützt Delphi 2005 die neue for Syntax nicht für die COM Kollektionen. Diese sind jedoch die, welche sich in Delphi mit am schwersten ansprechen lassen. Deshalb wäre es schon sehr angenehm das neue Konstrukt auch für diese nuzten zu können. Die in diesem Tutorial aufgezeigte Lösung bietet sich für über 95% aller COM Kollektionen an, da diese auf dem IEnumVariant Interface basieren, für andere Varianten kann dieser Code entsprechend angepasst werden. |
Re: for...in...do für COM Collections
Wie funktioniert diese for...in Schleife in Delphi Bevor ich den Code für COM Kollektionen erkläre werde ich zuerst aufklären, wie Delphi die for...in...do Syntax für Objekte unterstützt. Als Beispiel nehme ich eine Stringliste, fühle diese mit ein paar Werten und lese diese dann einzeln in einer for...in...do Schleife aus.
Delphi-Quellcode:
Der eigentlich interessante Teil ist folgender:
procedure TForm1.Button1Click(Sender: TObject);
var S: String; Strings: TStringList; begin Strings := TStringList.Create; try Strings.Add('1'); Strings.Add('2'); Strings.Add('3'); for S in Strings do ShowMessage(S); finally Strings.Free; end; end;
Delphi-Quellcode:
Wenn Delphi den Code kompiliert, dann werden diese zwei Zeilen ähnlich dem folgenden Code-Abschnitt umgesetzt:
for S in Strings do
ShowMessage(S);
Delphi-Quellcode:
Als erstes holt Delphi sich ein Enumerator-Objekt heran, welches genutzt wird, um die Liste aller Strings zu durchlaufen. Solange das Enumerator-Objekt weitere Strings liefern kann, wird der jeweils aktuelle String der Variablen "S" zugewiesen und somit verfügbar gemacht.
StringEnum := Strings.GetEnumerator;
try while StringEnum.MoveNext do begin S := StringEnum.Current; ShowMessage(S); end; finally StringEnum.Free; end; Hinweis Auf "S" kann innerhalb der for...in...do Schleife nur lesend zugegriffen werden. Gleiches gilt nicht, wenn man stattdessen obigen Code einsetzt. Damit es nicht zu Speicherlöchern kommt, wird der Code von Delphi automatisch in einen try...finally...end Block gesetzt. So wird das Enumerator-Objekt auch denn wieder freigegeben, wenn es innerhalb der Schleife zu einer Ausnahme (Exception) kommt. Delphi gibt den Enumerator immer wieder explizit frei. Daher kann ein Enumerator auch nur für eine Schleife genutzt werden und muss für jede Schleife erneut bereitgestellt werden. |
Re: for...in...do für COM Collections
Einen Enumerator für COM Kollektionen anbieten Als ich den Code für COM Kollektionen erstellt habe, habe ich mich gleichzeitig auf den Fakt gestützt, dass Delphi durch den try...finally...end Block sicherstellt, dass das Objekt auch wieder freigegeben wird. Da man aber ein fertiges COM Objekt nicht einfach um die nötigen Methoden erweitern kann, habe ich einen kleinen Umweg eingelegt. Eine Hilfsfunktion namens GetCOMEnumerator() erstellt ein Objekt, welches die von Delphi verlangte Methode GetEnumerator() integriert. Dieses Objekt wird an die for...in...do Schleife übergeben. Die Methode GetEnumerator() liefert einfach das Objekt zurück, welches diese implementiert. Somit wird das am Ende auch wieder freigegeben und der Speicher wieder aufgeräumt. Die interessanteste Methode des Objektes ist MoveNext:
Delphi-Quellcode:
Um den Enumerator jetzt einzubinden, muss man ihn wie folgend einbinden:
function TComEnumerator.MoveNext: Boolean;
var OleCurrent: OleVariant; Fetched: Cardinal; begin if FEnum <> nil then begin // fetch the next element from the collection list FEnum.Next(1, OleCurrent, Fetched); if Fetched = 1 then begin // another object was fetched FCurrent := OleCurrent; Result := True; end else begin // no more objects in enumaration Result := False; end; end else begin Result := False; end; end;
Delphi-Quellcode:
// iterate all drives
for Drive in GetCOMEnumerator(Drives._NewEnum) do // write the drive letter to the console WriteLn((Drive as IDrive).DriveLetter); |
Re: for...in...do für COM Collections
Der Quellcode für den COM Enumerator könnt Ihr in der
![]() ![]() Viel Spaß damit! ...:cat:... |
Re: for...in...do für COM Collections
Komme nicht auf Quality Central (ist wohl down). Könntest Du den Source hier vielleicht komplett pasten?
Danke und Grüße |
Re: for...in...do für COM Collections
Probier einfach ein paar mal F5. Hin und wieder kommt man drauf ;)
|
Re: for...in...do für COM Collections
Zitat:
...:cat:... |
Re: for...in...do für COM Collections
Habs via Google Cache geschafft. Tolles Teil Sakura! Das werde ich sicher noch oft brauchen.
Danke und Grüße |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:46 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz