Wednesday, May 11, 2011

Non-int array indexes from Delphi in C#

In Delphi, array indexes can be any type that resolves to an integer, not just integers. So for example, enum and bool types can be array indexes. This can be handy in many situations to reduce a if-then or switch construct to a simple assignment. A simple, contrived example:


MyEnum = (item1, item2, item3);
...
function enumToString(value: MyEnum): string
begin
switch(value)
case item1: result = "Item one";
case item2: result = "Item two";
case item3: result = "Item three";
end;
end;
...
SomeLabel.Caption = enumToString(value);
...

becomes something like this:


MyEnum = (item1, item2, item3);
enumToString[MyEnum]: string = ("Item one", "Item two", "Item three");
...
SomeLabel.Caption = enumToString[value];
...
Not only does it reduce code, it also reduces possible bugs. Consider what happens when a value is added to MyEnum. The first example will simply return an empty string creating a possible silent failure that hopefully will be caught when tests are run. The second will generate a compiler error, forcing the programmer to intentionally decide what to do.

In C#, array indexes must be one of the four integer types: int, uint, long or ulong. I really miss the ability to use bools and enums. While lamenting this lack as I looked at some code today similar to the original switch statement, I realized I could use a generic dictionary. The new code looks like this:

MyEnum = (item1, item2, item3);
enumToString = new Dictionary = {{item1, "Item one"}, {item2, "Item two"}, {item3, "Item three")};
...
SomeLabel.Contents = enumToString[value];
...
On one hand, it is a bit more wordy than the Delphi array; on the other, it's clearer how things are associated in the initializer. The biggest drawback is it doesn't have the compiler error when things are added to the enum. This is mitigated a bit by the runtime exception generated by a missing key; it's not quite as silent as just returning nothing in the original code. However, it still depends on good test coverage to find it.

No comments: