How to bulletproof the loops
Here is one example about how to bulletproof the loops. This example holds well for legacy code and - of course - for hurry-written-code (that might be the current one, unfortunately).
One of the most dangerous things I've seen are pieces of code that loop through object arrays and lists, same time expecting that array or list contains only correct elements. What do you think about ArrayList by example? Is it able to hold only those objects that are correct ones in current context or is ArrayList more powerful and can hold also incorrect objects?
Well, I'm always very suspicious when I see ArrayList or IList on .Net 2.0 code. I always ask myself one question: isn't it possible to refactor this code so there is List<ImportantClass> instead of ArrayList or IList? If it is possible then I will refactor this code.
Here's my example.
public void SaveChanges(ArrayList entries)
{
foreach(MyObject bizObject in entries)
{
if(bizObject.IsDirty)
bizObject.Save();
}
}
What bad things may happen?
- Entries may be null.
- It is possible that entries list contains nulls.
- It is possible that entries list contains entries that are impossible to cast to required type.
- On large arrays cast has some impact on performance.
One can argue now that it is possible to use try-catch here and suppress all the errors. No problem - you can do it - if you want to see some grey hair (color code: #EFEFEF) in mirror after couple of debugging sessions. Try-catch overuse has these bad side efects.
- It may suppress also these exceptions that are thrown out by IsDirty property or Save method.
- When exception is thrown then try-catch needs hell load of resources in some cases.
So, what kind of code should be the best shot (in my humbe opinion)? I consider something like this. Instead of List<MyObject> you can use the generic list or collections that fits your needs better.
public void SaveChanges(List<MyObject> entries)
{
if(entries == null)
return;
foreach(MyObject bizObject in entries)
{
if(bizObject == null)
continue;
if(bizObject.IsDirty)
bizObject.Save();
}
}
Of course, we can also add here exception handling if we need it but it has nothing to do with exceptions that can be easily avoided here. Also it is not possible anymore to add other objects that can cause cast exceptions to our list. And we will also win on performance because we are checking the objects instead of waiting for errors.
Happy looping, guys! :)