FxCop: Do not cast unnecessarily

You're being a good developer and running your class library code through FxCop to see how well your code is following Microsoft's .NET Framework Design Guidelines. You've got a pretty harmless section of code like this:

Shared Sub Foo(ByVal x As Object)
    If TypeOf x Is Module1 Then
        Dim m As Module1 = DirectCast(x, Module1)
        m.Main()
    End If
End Sub

FxCop spits out warning:

Do not cast unnecessarily

Why are you getting this error? And the resolution doesn't seem to help too much:

'x', a parameter, is cast to type 'VBConsoleApplication.Module1' multiple times in method
Module1.Foo(Object):Void. Cache the result of the 'as' operator or direct cast in order to
eliminate the redundant castclass instruction.

To understand why you're getting this error requires that you understand the different ways .NET can do casting. First off, let's talk about the C# "as" operator described in the FxCop rule resolution. The C# "as" operator will attempt a cast and return null if it fails -- instead of raising an InvalidCastException. The "as" operator uses the "isinst" IL instruction. There is no equivalent in the current version of VB.NET. VB.NET 2005 will have a "TryCast" which will do the same thing as the C# "as" operator.

When it comes to regular casting in C# (or the "DirectCast" statement in VB.NET), the IL "castclass" instruction is used. This one will attempt a cast and raise an InvalidCastException if it can't perform the cast. So the two opcodes perform the same thing, but they operate differently: the "isinst" is a cast that doesn't throw an exception and "castclass" is a cast that will throw an exception.

The reason you see a warning from FxCop in the code above is because the VB.NET "TypeOf" operator uses the "isinst" instruction. That's one cast that FxCop sees. And then the DirectCast compiles into a "castclass" instruction. So FxCop sees your code doing another cast on the same set of variables. Casting isn't cheap so FxCop recommends you cache the result of the "as" operator (C# only) like so:

Module1 m = x as Module1;
if( m != null )
    m.Main();
This performs the cast and gives you a reference to the proper object or gives you a null reference. Only one cast is done. Until VB.NET 2005, the only thing you can do is either Use a Try/Catch and catch the InvalidCastException or refactor your code so the cast isn't necessary. Of course, you can always ignore the FxCop rule in cases like this. :)

No Comments