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.


 


 

Comments (1)

  1. I’m not sure why this would be surprising.  The extended class is completely decoupled from the extension method.  e.g. the compilation of the extended class could have have occured before the existence of the extension method.  Therefore instantiation code must not be affected by an extension method because it can be compiled before the extension method is created.