Skip to content

Two casts are not better than one

C# has an interesting operator know as “is“. The is operator is used for execution-time type checking. It is a binary operator that returns a Boolean indicating whether or not the instance in question is in fact of the type specified as the second operand.

Here is an example:

using System;
class Example { static void Main() { Console.WriteLine("hello, world" is String); // True } }

Obviously this is a simple example but I am sure that the reader is capable of extrapolating more practical usages of is. There is an inherent problem with is however that many developers are not aware of:

Under the covers, the is operator uses a cast to make its determination.

Why is this a problem? The reason it it a problem is because the next step most developers take is to cast the instance to the type. This is viewed as a sort of “safe cast” since you know that the instance is of that type. Here is an example of this practice:

using System;
class Dog { public void Speak() { Console.WriteLine("Bark!"); } }
class Example { static void Main() { Object obj = new Dog();
if (obj is Dog) ((Dog)obj).Speak(); // Bark! } }

In this example there are actually two separate casts, the is and the explicit cast below it (inside the conditional statement). You shouldn’t cast more then once if you don’t need to do so. Also, the is check does not consider user-defined conversions (such as implicit and explicit cast operators) so is may return false for an instance that could have successfully been casted.

So what should we do instead?

Enter C#’s true safe casting operator: as. The as operator allows you do do an explicit cast on a type while avoiding any InvalidCastExceptions that may occur by assigning null to the variable if the cast fails.

Here is an example of how to use as:

using System;
class Dog { public void Speak() { Console.WriteLine("Bark!"); } }
class Example { static void Main() { Object obj = new Dog();
Dog dog = obj as Dog; if (dog != null) dog.Speak(); } }

This example only contains one cast and also allows you to avoid any exceptions that may occur at execution time.

So, the important thing to remember is that if you feel like you need to use is, most likely you ought to use as.

Note: Be careful that you are not using casting to solve a problem that would be better solved with polymorphism. If you find that you are doing multiple checks for different types, casting, and then calling methods on those types, you should reevaluate your approach to see if a polymorphic solution would be better. Casting is a powerful tool but it can be misapplied.

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*