Art Of Programming

musings by Dmytrii Nagirniak

Prefer C# Cast but Not as Operator

I see misuse of these 2 operators on every and each forum approximately at least couple of times a week. People don’t know/realise (or don’t want to) that there is significant difference in two code snippets below (I found similar on one of the forums):
var unknown = (object)new List<string>();

// Snippet 1: as operator
foreach (var item in unknown as IList<int>) {
 // Do something with item
}


// Snippet 2: cast operator
foreach (var item in (IList<int>)unknown) {
 // Do something with item
}

Both snippets will throw an exception. But, there is a big BUT.
The first snippet will throw NullReferenceException (Object reference not set to an instance of an object). Go and guess what’s going on. Especially in production when you probably don’t have call stack with code line information, especially in just a bit more complex scenario. No useful information here at all.
The second one will throw too, but it will be InvalidCastException (Unable to cast object of type ‘System.Collections.Generic.List`1[System.String]’ to type ‘System.Collections.Generic.IList`1[System.Int32]’).
See the difference? The later one tells you what exactly is wrong so you have a good starting point of fixing the issue.
Generally I would tell to never use AS operator (even if you think you know the exact type NOW, you cannot be sure tomorrow) unless:
  1. You explicitly expect different type(s).
  2. You want to determine type using IS operator (really bad practice, consider simple polymorphism instead).
  3. You want to improve performance (though it is really, really rarely worth it).

Additionally, in any case you should check the casting result for null. Always check it for null. Do you hear me? ALWAYS!

Comments

Dmytrii Nagirniak
Rick, you are absolutly right. There is no reason to use casting in the foreach as it will implicitly call GetEnumerator on the object which in turn can give NullReferenceException.

The code I showed here is an example I saw on a forum, so just reused it. The issue you pointed out is a valid and major one. But I did not terget it in my post here… Well… I at least told to ALWAYS check for null :)… Should just add to check for null everything.
Rick W
Hmmm, I would say "Never write it either of these ways if there is any chance it will throw an exception". If you are not in 100% control of what object is being used as the enumerable object, you should use var LoopObj = obj as TypeX and then check Abc for null before you use it in the loop. If you are in control of the object, then it still depends on if it is possible that the object might be possibly be null on it's own, in which case I will still do it as I advise.

Rick W (from Eco forum)

Comments