Tuesday, April 03, 2007

DN4DP#6: Enumerating collections

This post continues the series of The Delphi Language Chapter teasers from Jon Shemitz’ .NET 2.0 for Delphi Programmers book. Last time we showed how it is now possible to override the meaning of language operators. This time we'll cover the new for in loop and the pattern for introducing enumeration support to your own classes.

Note that I do not get any royalties from the book and I highly recommend that you get your own copy – for instance at Amazon.

"Enumerating collections

To make it easier and more convenient to enumerate over the contents of collections the traditional for statement has been extended into a for in statement. In general the for in syntax is

var
Element: ElementType;
begin
for Element in Collection do
Writeln(Element.Member);
end;

ElementType must be assignment compatible with the type of the actual elements stored inside the collection. The collection must implement the enumerator pattern or be of an array, string or set type. You only have read access to the Element itself, but you can change any properties and fields it references.

All .NET collections and most VCL container classes like TList and TStrings implements the required pattern, so now you can transform old code like

var
S: string;
i: integer;
begin
for i := 0 to MyStrings.Count-1 do
begin
S := MyStrings[i];
writeln(S);
end;
end;

into the simpler, less error prone, but equivalent

var
S: string;
begin
for S in MyStrings do
writeln(S);
end;

To enable for in for your own collection classes, you need to implement the enumerator pattern. This involves writing a GetEnumerator function that returns an instance (class, record or interface) that implements a Boolean MoveNext function and a Current property. In .NET you can also achieve this by implementing the IEnumerable interface. In Win32 these methods must be public.

type
TMyObjectsEnumerator = class
public
function GetCurrent: integer;
function MoveNext: Boolean;
property Current: integer read GetCurrent;
end;
TMyObjects = class
public
function GetEnumerator: TMyObjectsEnumerator;
end;

The EnumeratingCollections project demonstrates the differences between the old manual enumeration loops and the new for in loops. It also includes an example of how to write your own classes that support for in enumeration."

1 comment:

gabr42 said...

I'd like to abuse this comment to link to my own (long) treatise on enumerators. :)

Hallvard, if this is out of line, freely delete this comment.



Copyright © 2004-2007 by Hallvard Vassbotn