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>

0 komentarzy