Option Strict Off: A force for Good?

Category: visual studio vb

Question

Reed Kimble on Thu, 07 Apr 2016 20:28:58


Many of us who frequently contribute to this forum can be quoted numerous times saying "set Option Strict On at the top of your code file".  We use Option Strict religiously... if Option Strict were "The Force" from "Star Wars" then "Option Strict On" would be the Light-Side and "Option Strict Off" would be the Dark-Side.  I have seen the words "Option Strict Off" and "Evil" in the same sentence before.

This is a common and justly deserved viewpoint amongst many long-time VB.Net developers.  For most of the history of VB.Net, the only real purpose for Option Strict Off was to support the conversion of old VB6 code.  Any new development using late-binding was highly discouraged.  And for good reason; the performance impact of late binding is substantial and adds up quickly with repeated use.  It also makes it impossible for the editor to assist you with intellisense and design-time error checking, making your code more prone to mistakes.

But over the past few years there has been some heavy adoption of dynamic languages like JavaScript, Python, Ruby, PHP, Lua and more.  While some have risen and fallen (Ruby/Python, PHP?), others are here to say (JavaScript, Lua) and new ones continue to rise.  So not be outdone, .Net added a solution to allow its existing languages to exhibit dynamic-language-like behavior through System.Dynamic. 

By inheriting from System.Dynamic.DynamicObject you can create an instance of a dynamic object whose members can be modified at runtime.  In C# this is done through a special "dynamic" keyword, but guess how it is implemented in VB.Net?  That's right, through the existing late-binding model.

In VB.Net you utilize a DynamicObject instance by declaring a variable as type Object, setting it to a new instance of the Dynamic type, and then using late-bound member access to work with the instance.  You still suffer from a lack of intellisense, but the performance impact is no where near that of traditional late binding.  It not as fast as early bound member access or quite as fast as reflection, but still much faster than traditional late-bound access.  So considering the number of possibilities that DynamicObject creates, the performance cost is acceptable.

Here's a little demo to compare traditional early bound code with late bound code, dynamic code, and reflection.

Option Strict Off
Imports System.Dynamic

Public Class LateBoundCompareForm
    Friend WithEvents TestButton As New Button With {.AutoSize = True, .Text = "Run Test"}
    Friend WithEvents ListBox1 As New ListBox With {.Top = TestButton.Height + 4}

    Private Sub LateBoundCompareForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Controls.Add(TestButton)
        Controls.Add(ListBox1)
    End Sub

    Private Sub TestButton_Click(sender As Object, e As EventArgs) Handles TestButton.Click
        Dim sw As New Stopwatch

        'baseline/control, early-bound
        Dim strongPerson As Person = New Person
        strongPerson.Age = 0
        strongPerson.Name = ""
        sw.Start()
        For i = 1 To 100
            strongPerson.Age = i
            strongPerson.Name = i.ToString
        Next
        sw.Stop()
        '~ 0.01ms or less
        ListBox1.Items.Add(sw.Elapsed.TotalMilliseconds.ToString("N5"))

        'late-bound
        Dim loosePerson As Object = New Person
        loosePerson.Age = 0
        loosePerson.Name = ""
        sw.Restart()
        For i = 1 To 100
            loosePerson.Age = i
            loosePerson.Name = i.ToString
        Next
        sw.Stop()
        '~ 0.5ms or more (as high as 1.5ms)
        ListBox1.Items.Add(sw.Elapsed.TotalMilliseconds.ToString("N5"))

        'dynamic
        Dim dynamicPerson As Object = New DynamicPropertiesObject
        dynamicPerson.Age = 0
        dynamicPerson.Name = ""
        sw.Restart()
        For i = 1 To 100
            dynamicPerson.Age = i
            dynamicPerson.Name = i.ToString
        Next
        sw.Stop()
        '~ 0.09ms give or take 0.01ms
        ListBox1.Items.Add(sw.Elapsed.TotalMilliseconds.ToString("N5"))

        'reflected
        Dim reflectedPerson As Person = New Person
        reflectedPerson.Age = 0
        reflectedPerson.Name = ""
        Dim ageProp = reflectedPerson.GetType.GetProperty("Age", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)
        Dim nameProp = reflectedPerson.GetType.GetProperty("Name", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)
        sw.Restart()
        For i = 1 To 100
            ageProp.SetValue(reflectedPerson, i)
            nameProp.SetValue(reflectedPerson, i.ToString)
        Next
        sw.Stop()
        '~ 0.15ms give or take 0.02ms
        ListBox1.Items.Add(sw.Elapsed.TotalMilliseconds.ToString("N5"))
    End Sub
End Class

Public Class Person
    Public Property Name As String
    Public Property Age As Integer
End Class

Public Class DynamicPropertiesObject
    Inherits DynamicObject

    Private properties As New Dictionary(Of String, Object)

    Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder, ByRef result As Object) As Boolean
        If properties.TryGetValue(binder.Name, result) Then
            Return True
        End If
        Return False
    End Function

    Public Overrides Function TrySetMember(ByVal binder As SetMemberBinder, ByVal value As Object) As Boolean
        properties(binder.Name) = value
        Return True
    End Function
End Class

This example just sets the Name and Age properties of a Person object instance 100 times and measures how long it takes to do that.  The example is using the simplest possible DynamicObject implementation which only handles property access.  DynamicObject has a lot of overridable methods to allow very granular control over the dynamic behavior of your objects.

That means we can do a lot of really neat things.

Ever have a situation where it would be really handy to use some JavaScript-like functionality?  Well, with DynamicObject and late binding you could do that.  The following code example is just a thought-experiment/proof-of-concept and isn't ready to be used as an object model on its own (though it may represent the scaffolding from which a reusable object model can be made).

This DynamicObject implementation offers "fields" and "properties" on objects where fields are members whose name begins with an underscore and whose values are an object instance.  Properties are all functions which take an optional, arbitrary argument array and return an optional object value.  This creates the basis of a JavaScripty/FSharpy kind of object model where all members are functions which can be defined and called willy-nilly (that is, whenever and wherever you want).  Here's the "FunctionalObject":

Public Class FunctionalObject
    Inherits DynamicObject

    Public Property [Property] As New FunctionalObjectPropertyCollection(Of String)
    Public Property Fields As New Dictionary(Of String, Object)

    Public Overrides Function GetDynamicMemberNames() As IEnumerable(Of String)
        Return [Property].Keys
    End Function

    Public Overrides Function TryInvokeMember(binder As InvokeMemberBinder, args() As Object, ByRef result As Object) As Boolean
        If [Property].TryGetValue(binder.Name, result) Then
            If args.Length > 0 Then
                Try
                    result = result.Invoke(New ArgumentArray(args))
                Catch missingEx As MissingMemberException
                    result = result.Invoke()
                End Try

            Else
                Try
                    result = result.Invoke()
                Catch missingEx As MissingMemberException
                    result = result.Invoke(ArgumentArray.Empty)
                End Try
            End If
            Return True
        End If
        Return False
    End Function

    Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder, ByRef result As Object) As Boolean
        If binder.Name.StartsWith("_") Then
            Return Fields.TryGetValue(binder.Name, result)
        Else
            If [Property].TryGetValue(binder.Name, result) Then
                result = result.Invoke()
                Return True
            End If
        End If
        Return False
    End Function

    Public Overrides Function TrySetMember(ByVal binder As SetMemberBinder, ByVal value As Object) As Boolean
        If binder.Name.StartsWith("_") Then
            Fields(binder.Name) = value
        Else
            [Property](binder.Name) = value
        End If
        Return True
    End Function

    Public Class FunctionalObjectPropertyCollection(Of T)
        Inherits SortedList(Of String, [Delegate])
    End Class

    Public Class ArgumentArray
        Public Shared ReadOnly Empty As New ArgumentArray({})

        Private listCore As New List(Of Object)
        Public Sub New(args As IEnumerable)
            listCore.AddRange(args)
        End Sub

        Public ReadOnly Property Count As Integer
            Get
                Return listCore.Count
            End Get
        End Property

        Default Public Property Item(index As Integer)
            Get
                If index > -1 AndAlso index < listCore.Count Then
                    Return listCore(index)
                End If
                Return Nothing
            End Get
            Set(value)
                If index > -1 AndAlso index < listCore.Count Then
                    listCore(index) = value
                End If
                If index < 0 Then
                    listCore.Insert(Math.Abs(index) - 1, value)
                Else
                    listCore.Add(value)
                End If
            End Set
        End Property
    End Class
End Class

With this object you can write some pretty crazy looking (in VB.Net terms) code which works perfectly:

Dim fo As Object = New FunctionalObject

'set an internal field value
fo._Name = "Foo"

'add a property through the property collection
fo.Property("Name") = Function()
                          Return fo._Name
                      End Function

'add properties directly
fo.Count = Function()
               Return 1
           End Function

fo.SetValue = Function(args)
                  fo._Value = args(0)
                  Return Nothing
              End Function

fo.GetValue = Function()
                  Return fo._Value
              End Function

fo.AddValue = Function(args)
                  fo._Value += args(0) + args(1)
                  Return Nothing
              End Function

fo.Add = Function(args)
             Dim total As Integer
             For i = 0 To args.Count - 1
                 total += args(i)
             Next
             Return total
         End Function

'override existing property
fo.OldSetValue = fo.Property("SetValue")
fo.SetValue = Function(args)
                  fo.OldSetValue(args(0))
                  fo._Value += args(0)
                  Return Nothing
              End Function

fo.GetXes = Function(args)
                Dim count As Integer = fo.GetValue
                If args.Count > 0 Then
                    count += args(0)
                End If
                Dim sb As New Text.StringBuilder
                For i = 1 To count
                    sb.Append("X")
                Next
                Return sb.ToString
            End Function

Label1.Text = fo.Name
Label1.Text &= " " & fo.Count

fo.SetValue(3)
Label1.Text &= " " & fo.GetValue

fo.AddValue(1)
Label1.Text &= " " & fo.GetValue

Label2.Text = fo.Add(1)

While that might look kind of crazy to a VB.Net developer, to a JavaScript developer that code might look fairly straightforward.

And while it also might make a VB.Net developer cringe at the implied execution costs, its actually not nearly as bad as it would seem.  This DynamicObject implementation is a little heavier than the first one from earlier in the post so it executes a little more slowly, but it is still quite acceptable - especially given the interesting functionality that was gained.

Since many of us do spend so much time poo-pooing the use of Option Strict Off, I thought I might be good to highlight a situation where Option Strict Off can be used to positive benefit.  There's also been ongoing chatter in various channels about the place of VB in the .Net ecosystem and one argument is to focus on VB's strengths as a "dynamic language".  While the System.Dynamic thing is at the Framework level, VB.Net does have its whole late-binding model worked out nicely and creative use of System.Dynamic does offer VB the potential to provide a strong "dynamic language" experience.  It is an interesting angle to think about.


Reed Kimble - "When you do things right, people won't be sure you've done anything at all"



Replies

leshay on Thu, 07 Apr 2016 20:41:32


Hi

All I know is that once I started using it, I had a *lot* better code.

Steve Parrish on Thu, 07 Apr 2016 21:18:04


That's pretty cool & funky!

Frank L. Smith on Thu, 07 Apr 2016 21:21:06


And while it also might make a VB.Net developer cringe at the implied execution costs, its actually not nearly as bad as it would seem.

All I can do is ... gasp, profusely refusing to take part in that insanity!

There can be a substantial performance hit with late-binding. To veritably encourage it takes me aback.

Reed Kimble on Thu, 07 Apr 2016 21:50:43


And while it also might make a VB.Net developer cringe at the implied execution costs, its actually not nearly as bad as it would seem.

All I can do is ... gasp, profusely refusing to take part in that insanity!

There can be a substantial performance hit with late-binding. To veritably encourage it takes me aback.


Knowledge rests not upon truth alone, but upon error also. Carl Jung

As expected :)

Just remember, this is not using traditional late binding.  The performance is much closer to early binding.  <strike>Its faster than reflection!</strike>


Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


sqlguy on Thu, 07 Apr 2016 21:51:22


If you use VB for WPF then because of the disconnected nature of WPF there are lots of places where you need to remove that option.

Frank L. Smith on Thu, 07 Apr 2016 21:53:23


Its faster than reflection!

That's not saying a lot...



Knowledge rests not upon truth alone, but upon error also. Carl Jung


Cor Ligthert on Thu, 07 Apr 2016 22:14:03


Reed,

The languages you mention are not used because they give better programs. 

They are used because some web developers don't understand anything about strongly typing, the same complaint was by VB6 developers, they had to think about more. 

The languages you name which are dynamic, sounds good but nobody ever looks in the English or American English dictonary what it means. In fact it means in both versions of English something unpredictable is done.

 

Most browsers have as default Error detecting off to avoid that pages made with those dynamic languages constantly stop running and when you set it on, after a day you set it off, most web pages are full of program errors. 

But I know, some find the word "dynamic" sounds great, it sounds like that you get everything for nothing. 

Be aware, I have also written like you. Armin Zingler and I had big discussions, but in fact I had to agree with him. 

I dropped it (constantly) at the team (with suggestions). That is where Option Infer originate.

In fact the only time I set Options Strict off is when I have trouble to find the type but have to know it. Intellisence gives me than the type.


Success
Cor




Dave299 on Thu, 07 Apr 2016 22:24:50


Just remember, this is not using traditional late binding.  The performance is much closer to early binding.  Its faster than reflection!

I don't think so.

There's a flaw in your test Reed: you are using sw.Start instead of Restart in the reflection test so it will always be slower than the dynamic test.

I've re-arranged the test a little to include the 'initial setup' as well as the loop and to allow repeat tests, which shows some very interesting results.

Option Strict Off
Option Infer On
Imports System.Dynamic
Public Class Form1
   Friend WithEvents TestButton As New Button With {.AutoSize = True, .Text = "Run Test"}
   Friend WithEvents ListBox1 As New ListBox With {.Top = TestButton.Height + 4, .Height = 350}
   Private Sub LateBoundCompareForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
      Height = 400
      Controls.Add(TestButton)
      Controls.Add(ListBox1)
   End Sub
   Private Sub TestButton_Click(sender As Object, e As EventArgs) Handles TestButton.Click
      ListBox1.Items.Clear() : ListBox1.Refresh()
      Dim TestCount As Integer = 10
      Dim sw As New Stopwatch
      For count As Integer = 1 To 3
         TestCount = TestCount * 10
         ListBox1.Items.Add("Total tests = " & TestCount.ToString)
         'baseline/control, early-bound
         sw.Start()
         Dim strongPerson As Person = New Person
         strongPerson.Age = 0
         strongPerson.Name = ""
         For i = 1 To TestCount
            strongPerson.Age = i
            strongPerson.Name = i.ToString
         Next
         sw.Stop()
         '~ 0.01ms or less
         ListBox1.Items.Add("Base line: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         'late-bound
         sw.Restart()
         Dim loosePerson As Object = New Person
         loosePerson.Age = 0
         loosePerson.Name = ""
         For i = 1 To TestCount
            loosePerson.Age = i
            loosePerson.Name = i.ToString
         Next
         sw.Stop()
         '~ 0.5ms or more (as high as 1.5ms)
         ListBox1.Items.Add("Late bound: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         'dynamic
         sw.Restart()
         Dim dynamicPerson As Object = New DynamicPropertiesObject
         dynamicPerson.Age = 0
         dynamicPerson.Name = ""
         For i = 1 To TestCount
            dynamicPerson.Age = i
            dynamicPerson.Name = i.ToString
         Next
         sw.Stop()
         '~ 0.09ms give or take 0.01ms
         ListBox1.Items.Add("Dynamic: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         'reflected
         sw.Restart()
         Dim reflectedPerson As Person = New Person
         reflectedPerson.Age = 0
         reflectedPerson.Name = ""
         Dim ageProp = reflectedPerson.GetType.GetProperty("Age", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)
         Dim nameProp = reflectedPerson.GetType.GetProperty("Name", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)
         For i = 1 To TestCount
            ageProp.SetValue(reflectedPerson, i, Nothing)
            nameProp.SetValue(reflectedPerson, i.ToString, Nothing)
         Next
         sw.Stop()
         '~ 0.15ms give or take 0.02ms
         ListBox1.Items.Add("Reflected: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         ListBox1.Items.Add("")
      Next
   End Sub
End Class

Public Class Person
   Public Property Name As String
   Public Property Age As Integer
End Class

Public Class DynamicPropertiesObject
   Inherits DynamicObject
   Private properties As New Dictionary(Of String, Object)
   Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder, ByRef result As Object) As Boolean
      If properties.TryGetValue(binder.Name, result) Then
         Return True
      End If
      Return False
   End Function
   Public Overrides Function TrySetMember(ByVal binder As SetMemberBinder, ByVal value As Object) As Boolean
      properties(binder.Name) = value
      Return True
   End Function
End Class


On the first run reflection is the quickest, it's only when you repeat the test that early bound becomes quicker.  It also shows how slow the initial set up is for the dynamic case.

Reed Kimble on Thu, 07 Apr 2016 22:29:12


Reed,

The languages you mention are not used because they give better programs. 

...

Hi Cor,

I didn't intend to address why those other languages gained popularity, only that they became popular.  As for web browsers, JavaScript is pretty much the go-to client-side script solution and you find it everywhere. So I don't think a lack of understanding strongly typed languages contributes to the success of those other dynamic languages; they each stand on their own merits. But we digress...

The point here was to highlight the fact that some of the advantages offered by purely dynamic languages, the things that really make those languages popular, can also be achieved in a strongly-typed language like VB.Net becaue VB.Net is so powerful and versatile... much more so than the developer industry as a whole recognizes.  This isn't really about debating whether or not dynamic languages offer any advantages; for the purpose of this thread we should take it at face value that they do.

Cor Ligthert on Fri, 08 Apr 2016 10:00:31


Hi guys, 

It seems I miss here something. Reflection is late binding the same as Option Strict Off uses. The speed is however very unpredictable but one thing is for sure; With Reflection is the chance on errors as high as with Option strict off. 

(It simply tries to find the first name of an identifier, if there are two the same (not impossible) it always takes the first, where you cannot influence the build order yourself).

Dave299 on Fri, 08 Apr 2016 11:08:55


Well as my post seems to have been totally ignored I will say it again.

The reason using dynamic objects appears to be faster than reflection is because of an error in the test which causes the reflection test time to be added to the dynamic test time.

Cor Ligthert on Fri, 08 Apr 2016 11:54:49


Well as my post seems to have been totally ignored I will say it again.


Dave,

Then you did not see my reply on your message containing this or ignores that :-)

Dave299 on Fri, 08 Apr 2016 17:09:14


Sorry Cor, I wasn't in threaded view mode and so didn't realise that "Hi guys" was addressed to me :)

Reed Kimble on Fri, 08 Apr 2016 18:04:50


Just remember, this is not using traditional late binding.  The performance is much closer to early binding.  Its faster than reflection!

I don't think so.

There's a flaw in your test Reed: you are using sw.Start instead of Restart in the reflection test so it will always be slower than the dynamic test.

I've re-arranged the test a little to include the 'initial setup' as well as the loop and to allow repeat tests, which shows some very interesting results.

Option Strict Off
Option Infer On
Imports System.Dynamic
Public Class Form1
   Friend WithEvents TestButton As New Button With {.AutoSize = True, .Text = "Run Test"}
   Friend WithEvents ListBox1 As New ListBox With {.Top = TestButton.Height + 4, .Height = 350}
   Private Sub LateBoundCompareForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
      Height = 400
      Controls.Add(TestButton)
      Controls.Add(ListBox1)
   End Sub
   Private Sub TestButton_Click(sender As Object, e As EventArgs) Handles TestButton.Click
      ListBox1.Items.Clear() : ListBox1.Refresh()
      Dim TestCount As Integer = 10
      Dim sw As New Stopwatch
      For count As Integer = 1 To 3
         TestCount = TestCount * 10
         ListBox1.Items.Add("Total tests = " & TestCount.ToString)
         'baseline/control, early-bound
         sw.Start()
         Dim strongPerson As Person = New Person
         strongPerson.Age = 0
         strongPerson.Name = ""
         For i = 1 To TestCount
            strongPerson.Age = i
            strongPerson.Name = i.ToString
         Next
         sw.Stop()
         '~ 0.01ms or less
         ListBox1.Items.Add("Base line: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         'late-bound
         sw.Restart()
         Dim loosePerson As Object = New Person
         loosePerson.Age = 0
         loosePerson.Name = ""
         For i = 1 To TestCount
            loosePerson.Age = i
            loosePerson.Name = i.ToString
         Next
         sw.Stop()
         '~ 0.5ms or more (as high as 1.5ms)
         ListBox1.Items.Add("Late bound: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         'dynamic
         sw.Restart()
         Dim dynamicPerson As Object = New DynamicPropertiesObject
         dynamicPerson.Age = 0
         dynamicPerson.Name = ""
         For i = 1 To TestCount
            dynamicPerson.Age = i
            dynamicPerson.Name = i.ToString
         Next
         sw.Stop()
         '~ 0.09ms give or take 0.01ms
         ListBox1.Items.Add("Dynamic: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         'reflected
         sw.Restart()
         Dim reflectedPerson As Person = New Person
         reflectedPerson.Age = 0
         reflectedPerson.Name = ""
         Dim ageProp = reflectedPerson.GetType.GetProperty("Age", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)
         Dim nameProp = reflectedPerson.GetType.GetProperty("Name", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)
         For i = 1 To TestCount
            ageProp.SetValue(reflectedPerson, i, Nothing)
            nameProp.SetValue(reflectedPerson, i.ToString, Nothing)
         Next
         sw.Stop()
         '~ 0.15ms give or take 0.02ms
         ListBox1.Items.Add("Reflected: " & sw.Elapsed.TotalMilliseconds.ToString("N5"))
         ListBox1.Items.Add("")
      Next
   End Sub
End Class

Public Class Person
   Public Property Name As String
   Public Property Age As Integer
End Class

Public Class DynamicPropertiesObject
   Inherits DynamicObject
   Private properties As New Dictionary(Of String, Object)
   Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder, ByRef result As Object) As Boolean
      If properties.TryGetValue(binder.Name, result) Then
         Return True
      End If
      Return False
   End Function
   Public Overrides Function TrySetMember(ByVal binder As SetMemberBinder, ByVal value As Object) As Boolean
      properties(binder.Name) = value
      Return True
   End Function
End Class


On the first run reflection is the quickest, it's only when you repeat the test that early bound becomes quicker.  It also shows how slow the initial set up is for the dynamic case.

Good catch on Start vs Restart, that was a typo.

But it doesn't change the results on my system like you show.  This puts reflection between early binding and dynamic binding: 0.01 early, 0.07 reflected, 0.12 dynamic, 0.52 late.  I'm not sure how you could get reflection to beat early binding... are you sure you read the results correctly?

I also intentionally skipped the time it takes to set the dynamic properties initially - the test was only about the time it takes to set the member once it exists.

So I have to take back the "faster than reflection" comment, but its still way faster than traditional late binding.

Reed Kimble on Fri, 08 Apr 2016 18:06:06


Well as my post seems to have been totally ignored I will say it again.

...

Your post didn't show up until today. I didn't see it here last night.

Crazypennie on Fri, 08 Apr 2016 21:36:51


A bit off topic, but good to know:

.

System Dynamic implements the type "Variant"

(Undocumented .. and difficult to access ... but useful to know when dealing with cpp)

.

 === Works only with Option Strict Off

.


In the code I create a variant  ... assign a integer to it , then a Boolean and finally a Double

    ''' <remark>
    ''' Defined Variant Type:
    '''    AsBool, AsBstr, AsCy, AsDate, AsDecimal, AsDispatch, AsError, AsI1, AsI2, AsI4
    '''    AsI8, AsInt, AsR4, AsR8, AsUi1, AsUi2, AsUi4, AsUi8, AsUint, AsUnknown, AsVariant
    '''    
    ''' Imports System.Runtime.InteropServices.VarEnum
    ''' </remark>
    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click

        Dim DynAssembly As Assembly = Reflection.Assembly.LoadFrom("C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\System.Dynamic.dll")
        Dim [Variant] As Type = DynAssembly.GetType("System.Dynamic.Variant")
        Dim MyVariant = Activator.CreateInstance([Variant])

        MyVariant.AsInt = 33

        MyVariant.AsBool = True
        Dim BB As Boolean = MyVariant.AsBool
        If MyVariant.VariantType = VT_BOOL Then Stop


        MyVariant.AsR8 = 123.456
        Dim DD As Double = MyVariant.AsR8
        If MyVariant.VariantType = VT_R8 Then Stop
    End Sub

Reed Kimble on Fri, 08 Apr 2016 21:45:11


Definitely good to know!  Very cool Luc!

Dave299 on Sat, 09 Apr 2016 11:40:02


I'm not sure how you could get reflection to beat early binding... are you sure you read the results correctly?

Definitely not misreading them.  It puzzled me for a little while but the reason appears to be that the first access of the Person class takes a long time, and because I included the variable declaration and assignment in the timing whichever test is run first suffers from that time whereas the subsequent tests are not affected.  To get more consistent results I ran a 'dummy' test before starting the real tests and got much more consistent results.