Programowanie w języku Delphi » Gotowce

Implementacja Foreach (for in do) dla Delphi 7

  • 2012-11-15 16:59
  • 0 komentarzy
  • 2327 odsłon
  • Oceń ten tekst jako pierwszy


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


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.


Przykład wykorzystania #1


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


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
  1. Delphi 6 Items
  2. Foreach - Wikipedia