Implementacja Foreach (for in do) dla Delphi 7
papudrun
1 Słowem wstępu
2 Kod modułu
3 Przykład wykorzystania #2
Słowem wstępu
Podczas pisania jednego z programów spotkałem się z problemem braku możliwości wykorzystania foreach w Delphi 7. Począwszy od Delphi 2005 możliwe jest wykorzystanie następującej składni:for enumerator in collection do
begin
//do something here
end;
Aby ten sam efekt uzyskać w starszych wersjach Delphi musimy pokombinować. Wykorzystamy do tego następujący moduł:
Kod modułu
```delphi unit foreach;interface
type
IForEach = interface
function Next(var item: OleVariant): boolean;
procedure Reset();
end;
function makeForEach(collection: IDispatch): IForEach;
// ==================================================================
implementation
uses
Windows,
SysUtils,
ActiveX;
type
TForEach = class(TInterfacedObject, IForEach)
fEnum : IEnumVARIANT;
constructor Create(collection: IDispatch);
function Next(var item: OleVariant): boolean;
procedure Reset();
end;
// ==================================================================
function makeForEach(collection: IDispatch): IForEach;
begin
Result := TForEach.Create(collection);
end;
// ==================================================================
{ TForEach }
constructor TForEach.Create(collection: IDispatch);
var
invokeResult : OleVariant;
disppar : DISPPARAMS;
hr : HRESULT;
begin
VariantInit(invokeResult);
zeromemory(@disppar, sizeof(DISPPARAMS));
hr := collection.Invoke(DISPID_NEWENUM, GUID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET,
disppar, @invokeResult, nil, nil);
if SUCCEEDED(hr) then begin
fEnum := IUnknown(invokeResult) as IEnumVARIANT;
VariantClear(invokeResult);
if fEnum = nil then
raise Exception.Create('Collection does not support IEnumVARIANT');
Reset();
end else begin
raise Exception.Create('Collection does not return an enumerator');
end;
end;
// ------------------------------------------------------------------
function TForEach.Next(var item: OleVariant): boolean;
var
nFetched : cardinal;
newItem : OleVariant;
begin
Result := False;
if fEnum <> nil then begin
VariantInit(newItem);
if SUCCEEDED(fEnum.Next(1, newItem, nFetched)) then begin
if nFetched > 0 then begin
item := newItem;
VariantClear(newItem);
Result := True;
end;
end;
end;
end;
// ------------------------------------------------------------------
procedure TForEach.Reset;
begin
Assert(fEnum <> nil);
fEnum.Reset();
end;
// ------------------------------------------------------------------
end.
<h1>Przykład wykorzystania #1</h1>
```delphi
var
foreach : IForEach;
en : IEnumSomething;
item : ISomething;
varitem : OleVariant;
begin
// DoSomething() returns a collection
en := DoSomething() as IEnumSomething;
foreach := makeForEach(en);
while foreach.Next(varitem) do begin
item := IUnknown(varitem) as ISomething;
item.GreatFunction();
end;
Przykład wykorzystania #2
```delphi var ExcelApp: Variant; foreach : IForEach; collection : Variant; collection_item: Variant; varitem : OleVariant; {...} collection := ExcelApp.WorkSheets[1].Range['D5:D300']; foreach := makeForEach(collection);while foreach.Next(varitem) do begin
collection_item := varitem;
if Trim(collection_item.Text)<>'' then begin
Memo1.lines.add(collection_item.Text);
end;
end;
____
Źródła
#<a href="http://www.wehlou.com/Code/d6_items.htm#Foreach">Delphi 6 Items</a>
#<a href="http://en.wikipedia.org/wiki/Foreach#Delphi">Foreach - Wikipedia</a>