Udostępnij za pośrednictwem


Performance techniques for converting Object to structures

If you're
converting Object expressions to
structures, you can tweak your code for a drastic performance improvement.

Because unboxing a Nothing
reference throws an exception, a conversion from Object to a structure involves testing for a Nothing reference before performing the unbox. For
example:

Structure
Foo

    Public a As Integer

    Public b As Integer

End
Structure

Module
Test

    Sub Foo(ByVal o As Object)

        Dim x As Foo

        x = o

    End Sub

End
Module

The
compiler actually generates this code behind the scenes:

Module
Test

    Sub Foo(ByVal o As Object)

        Dim x As Foo

        Dim _t As Object = o

        If _t Is Nothing
Then

            _t = System.Activator.CreateInstance(GetType(Foo))

        End If

        x = DirectCast(_t, Foo)

    End Sub

End
Module

In the
case that o is Nothing, x gets a zeroed-out, or default, instance of Foo. Getting this default instance of Foo is costly
because the compiler uses System.Activator.CreateInstance to create one.

You can
avoid the call to System.Activator.CreateInstance
by performing the Nothing check by
hand and supplying a ready-made default instance of your structure. There are two techniques I can think of to
supply a ready-made default, either by using a local variable or, slightly
safer, a Shared ReadOnly
field declared on the structure itself.

Option 1:

Module
Test

    Sub Foo(ByVal o As Object)

        Dim x As Foo

        Dim DEFAULT As
Foo 'Don't ever modify this

        If o Is Nothing Then

            x = DEFAULT

     Else

            x = DirectCast(o, Foo)

        End If

    End Sub

End
Module

Option 2:

Structure
Foo

    Public a As Integer

    Public b As Integer

    Public Shared ReadOnly
DEFAULT As Foo

End
Structure

Module
Test

    Sub Foo(ByVal o As Object)

        Dim x As Foo

        If o Is Nothing Then

            x = Foo.DEFAULT

        Else

            x = DirectCast(o, Foo)

        End If

    End Sub

End
Module

The nice
thing about Option 1 is that you can use this technique for any structure. However, Option 2 is the better choice
because, assuming you can modify the declaration of the structure, the compiler
will stop you from accidentally modifying the DEFAULT variable, thereby
preserving its clean state.

Note that
assigning Nothing
to a structure generates a call to CreateInstance as well.
You should use these techniques rather than assigning Nothing to a structure:

Module
Test

    Sub Foo(ByVal o As Object)

        Dim x As Foo

        x = Nothing 'Okay

        x = Foo.DEFAULT 'Better

    End Sub

End
Module

Also note
that these techniques pertain to Structures,
not intrinsic value types such as Byte,
Integer, Long, Double, etc. Casting from Object to Integer will not involve a call to CreateInstance.

We're
definitely looking at having the compiler use these same techniques (probably
Option 1 where the local will be an inaccessible temporary variable) in the
next version.

Comments

  • Anonymous
    July 22, 2003
    The comment has been removed
  • Anonymous
    July 23, 2003
    thanks! I've updated it.