SYSK 370: The Performance Cost of Extension Methods

First, for those who may not be familiar with this feature, .NET 3.5 allows developers to add methods to existing types without using inheritance or partial classes by creating static methods that can be invoked by using instance method syntax.

 

When I first heard about this feature, it reminded me of the decorator pattern in OOP (I’m not speaking of the implementation, but the concept… )

 

Since there are lots of examples for C# developers, and very few for VB.NET, here is an example of adding Serialize and Deserialize methods to any object written in VB.NET:

 

1. Add a module file to your project and paste the following code:

 

' TODO: need to add SEH and NULL handling!

' TODO: Check for object being marked with Serializable attribute

Module Module1

    <System.Runtime.CompilerServices.Extension()> _

    Public Function Serialize(ByVal o As Object) As String

        Dim data() As Byte

        Using ms As New System.IO.MemoryStream()

            Dim f As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

            f.Serialize(ms, o)

            data = ms.ToArray

        End Using

        Return Convert.ToBase64String(data)

    End Function

    <System.Runtime.CompilerServices.Extension()> _

    Public Function Deserialize(ByVal s As String) As Object

        Dim result As Object

        Dim data() As Byte = Convert.FromBase64String(s)

        Using ms As New System.IO.MemoryStream(data)

            Dim f As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter

            result = f.Deserialize(ms)

        End Using

        Return result

    End Function

End Module

2. Below is an example of using this extension method (the important lines are in bold):

Public Class Form2

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim t As New Test

        t.i = Integer.Parse(Me.TextBox1.Text)

        t.s = Me.TextBox2.Text

        Me.TextBox3.Text = t.Serialize()

    End Sub

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.TextBox1.Text = New Random().Next(1, 1000).ToString()

        Me.TextBox2.Text = "Time now is " + DateTime.Now().ToLongTimeString()

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Dim t As Test = Me.TextBox3.Text.Deserialize()

        Me.TextBox4.Text = t.i.ToString()

        Me.TextBox5.Text = t.s

    End Sub

End Class

<System.Serializable()> _

Public Class Test

    Private _s As String

    Public Property s() As String

        Get

            Return _s

        End Get

        Set(ByVal value As String)

            _s = value

        End Set

    End Property

    Private _n As New NestedTest

    Public Property i() As Integer

        Get

            Return _n.i

        End Get

        Set(ByVal value As Integer)

            _n.i = value

        End Set

    End Property

End Class

<System.Serializable()> _

Public Class NestedTest

    Private _i As Integer

    Public Property i() As Integer

        Get

            Return _i

        End Get

        Set(ByVal value As Integer)

            _i = value

        End Set

    End Property

End Class

 

Now, to the promised performance impact… I ran and timed a test that created 100,000,000 instances of an object with the extension methods above, and compared the execution time to doing the same but without the extension methods. Just to be clear, I didn’t actually execute the extension methods… My goal was to find out if simply adding the extension methods would significantly impact the object instantiation time by running the following code:

 

Dim t As New System.Diagnostics.Stopwatch

t.Start()

Dim o As Test

Dim i As Integer

For i = 0 To 100000000

o = New Test

o.i = 1

o = Nothing

Next

t.Stop()

System.Diagnostics.Debug.WriteLine(t.ElapsedMilliseconds().ToString())

 

To my surprise, my tests show that adding extension methods did not result in any measurable performance decrease. On my dual proc laptop with 4 Gb RAM, the results were as follows:

 

                   With Extension Methods Without Extension Methods

--------------------------------------------------------------------------------------

Run 1 4071 ms 3905 ms

Run 2 4118 ms 3916 ms

Run 3 4145 ms 3904 ms

Bottom line – it appears that using extension methods does not have any measurable performance hit on object instantiation time.