Why VB.Net Needs a Dynamic Keyword
I had just written a couple of blog posts about using the dynamic keyword with Json.Net when a coworker asked me about doing the same in Vb.Net. I told him that vb.net does not have a dynamic keyword as you’ve always been able to do runtime member binding, just turn option strict and option infer off. Something like this should work just fine.
Option Infer Off
Option Strict Off
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.Dynamic
Module Module1
Sub Main()
Dim user As String = "{'name':'Matthew Doig','link':'http://www.facebook.com/mattdoig'}"
Dim userJson = JObject.Parse(user)
Console.WriteLine(userJson.name)
Console.Read()
End Sub
End Module
Except it doesn’t work just fine, instead a MissingMemberException is thrown with the message: “public ‘member’ name on type ‘JObject’ not found”. Perusing the internet and the consensus seems to be to use the array syntax.
Option Infer Off
Option Strict Off
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.Dynamic
Module Module1
Sub Main()
Dim user As String = "{'name':'Matthew Doig','link':'http://www.facebook.com/mattdoig'}"
Dim userJson = JObject.Parse(user)
Console.WriteLine(userJson("name"))
Console.Read()
End Sub
End Module
And this does work, but it doesn’t answer the question why the dot syntax doesn’t. Runtime member binding is a feature VB.net has had since long before the dynamic keyword in csharp. So why doesn’t it work for Json.Net?
We take a quick look at the IL in reflector to see if there’s any difference between the c# and VB.Net programs. And lo and behold, vb generates the following call when making the late binding call.
RuntimeHelpers.GetObjectValue(
NewerLateBinding.LateGet(
myObject, null, "name", new object[0], null, null, null))
And if we make the same call from c# then we get the same exception message.
using System;
using System.Runtime.CompilerServices;
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json.Linq;
class Program
{
static void Main(string[] args)
{
var user = "{\"name\":\"Matthew Doig\"," +
"\"link\":\"http://www.facebook.com/mattdoig\"}";
dynamic userJson = JObject.Parse(user);
Console.WriteLine(userJson.name);
Console.WriteLine(RuntimeHelpers.GetObjectValue(
NewLateBinding.LateGet(
userJson, null, "name", new object[0], null, null, null)));
Console.Read();
}
}
So something in the LateGet method is causing our late bound call to a JObject to fail at runtime.
Looking through the source code of Json.Net and we find that the JObject overrides GetMetaObject to return an object responsible for the runtime binding operations on the object. This post details an object that uses the same methodology for runtime binding. The code simply logs when binding operations are called at runtime.
using System;
using System.Dynamic;
using System.Linq.Expressions;
public class MyDynamicObject : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new MyMetaObject(parameter, this);
}
public class MyMetaObject : DynamicMetaObject
{
public MyMetaObject(Expression parameter, object value)
: base(parameter, BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
return this.PrintAndReturnIdentity("InvokeMember of method {0}", binder.Name);
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
return this.PrintAndReturnIdentity("SetMember of property {0}", binder.Name);
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
return this.PrintAndReturnIdentity("GetMember of property {0}", binder.Name);
}
private DynamicMetaObject PrintAndReturnIdentity(string message, string name)
{
Console.WriteLine(String.Format(message, name));
return new DynamicMetaObject(
Expression,
BindingRestrictions.GetTypeRestriction(
Expression,
typeof(MyDynamicObject)));
}
}
}
And when we run the following code we see something rather interesting.
using System;
using System.Dynamic;
using System.Runtime.CompilerServices;
using DynamicObject;
using Microsoft.VisualBasic.CompilerServices;
class Program
{
static void Main(string[] args)
{
dynamic myObject = new MyDynamicObject();
myObject.name = "Matthew Doig";
Console.WriteLine(myObject.name);
Console.WriteLine(RuntimeHelpers.GetObjectValue(
NewLateBinding.LateGet(myObject, null, "name",
new object[0], null, null, null)));
Console.Read();
}
}
SetMember of property name GetMember of property name DynamicObject.MyDynamicObject InvokeMember of method name DynamicObject.MyDynamicObject
The myObject.name call results in a “GetMember of property name” while LateGet results in an “InvokeMember of method name”. So now it makes sense why late binding is not working for VB.Net.
Option Infer Off
Option Strict Off
Imports DynamicObject
Module Module1
Sub Main()
Dim myObject = New MyDynamicObject()
myObject.name = "Matthew Doig"
Console.WriteLine(myObject.name)
Console.Read()
End Sub
End Module
SetMember of property name InvokeMember of method name MyDynamicObject
The above code results in a call to BindInvokeMember instead of BindGetMember, and of course there is no method called “name” on the object. Because you can call methods without a () in VB, VB has no way to know whether its supposed to call BindInvokeMember or BindGetMember at runtime.
This is where a dynamic keyword would come in handy. The dynamic keyword would ensure you get the same behavior as csharp. Basically dynamic would tell the compiler not to emit a call to LateGet and simply let the dlr take care of the runtime binding.
2 Responses to “Why VB.Net Needs a Dynamic Keyword”
RSS feed for comments on this post. TrackBack URL








Thanks this helped in finding a solution, which was to use JSonFX to parse to dynamic instead
http://blogs.lessthandot.com/index.php/DesktopDev/MSTech/json-net-s-jobject-to
Comment by chrissie1 — November 11, 2012 @ 8:57 am
[...] took a look at how Json.Net works with the C# dynamic keyword and how Vb.net is unable to take advantage of the nicer runtime syntax provided by the dynamic keyword because of its legacy support for runtime bindings. Today, in the [...]
Pingback by Json and the F# Type Provider — November 26, 2012 @ 9:27 am