tags:

views:

108

answers:

3

I can't count how many times I may have erroneously done this:

for  i := 0 to MyList.count-1 do begin
  myobject := TMyObject(MyList[i])
  .......
end;

when it should be this:

for  i := 0 to MyList.count-1 do begin
  myobject := TMyObject(MyList.objects[i])
  .......
end;

Note the objects in the second snippet of code.

The erroneous snippet of code will run, and will obviously throw an access violation when I try to make use of myobject. But it isn't always apparent what it is I am doing wrong.

Is there a compiler option which will guard against this?

+5  A: 

No. The compiler assumes when you type-cast that you know what you're doing. It will allow pretty much any type-cast where the two types are the same size, with the notable exception of casting between integral and floating-point types.

For this particular instance, try getting yourself into the habit of using the as operator instead. Then the compiler will catch you when you forget to use the Objects property:

myobject := MyList[i] as TMyObject; // compiler error
myobject := MyList.Objects[i] as TMyObject; // OK
Rob Kennedy
He beat you by 3 minutes.
M Schenkel
@M Schenkel - You've got the minutes wrong way around. ;)
Sertac Akyuz
+7  A: 

Delphi has 2 ways to typecast, hardcast using TObject(var) and a softcast using the As operator. It is a good practice to always use the As operator unless you are 100% sure. In your specific example

(MyList[i]) as TMyObject does not compile where as

(MyList.objects[i]) as TMyObject does.

Daniel Maurić
Thanks. Yes - I will have to start getting into that habit.
M Schenkel
+3  A: 

It looks like you are using a TStringList to hold a string/object pair. If you are using Delphi 2009 or later an alternative suggestion is to replace your TStringList with a generic TDictionary like so:

uses
  Generics.Collections;
...
MyDictionary: TDictionary<String, TMyObject>;
...
for  MyObject in MyDictionary.Values do
begin
  ...
end;

Then the entire operation is type safe and you won't need to cast at all.

Note: You can't reassign the iteration variable inside a for..in loop (but you can call its methods and change the value of its properties.

codeelegance
+1. TStringList gets used as a Swiss Army Object far too often. This is probably a better answer than the accepted one, as long as the OP actually wants a string/object associative list and not a list of strings that happen to have objects attached.
Mason Wheeler