DynamicObject
class from the .NET's Dynamic Language Runtime. This class is an easy way to provide dynamic dispatch to your objects in a DLR language.Code samples presented here were created using Visual Studio 2010 Beta 1 so there may be differences with the final version.
The experiment
The example is a class that allows access to the properties of JSON objects using the property syntax of a DLR language. In order to do this, a wrapper to JSON.NET's JObject was created. This wrapper is called
FSDynJObjectWrapper
.The following code shows an example of using
FSDynJObjectWrapper
with C# 4.0 :
// Load the document
JsonTextReader reader = new JsonTextReader(GetTwitterPublicTimeLine());
JsonSerializer serializer = new JsonSerializer();
JArray topArray = (JArray)serializer.Deserialize(reader);
// Access the document
dynamic aObj = new FSDynJObjectWrapper((JObject)topArray[0]);
Console.WriteLine("========");
Console.WriteLine(aObj.user.screen_name);
Console.Write("\t'{0}'", aObj.text);
Given that the JSON returned by the Twitter REST api looks like this:
{"in_reply_to_screen_name":null,
"text":"...",
"user": { "following":null,
"description":"...",
"screen_name":"...",
"utc_offset":0,
"followers_count":10,
"time_zone":"...",
"statuses_count":155,
"created_at":"...",
"friends_count":1,
"url":"...",
"name":"...",
"notifications":null,
"protected":false,
"verified":false,
"favourites_count":0,
"location":"...",
"id": ...,
...
},
"truncated":false,
"created_at":"...",
"in_reply_to_status_id":null,
"in_reply_to_user_id":null,
"favorited":false,
"id":...,
"source":"...."
}
DLR and DynamicObject
The Dynamic Language Runtime provides a common infrastructure to build dynamic languages on the CLR. The
System.Dynamic.DynamicObject
class is an easy way to override the behavior of access to an object from a dynamic language. A partial definition of this class looks like this:
public abstract class DynamicObject : IDynamicMetaObjectProvider {
public virtual bool TryGetMember(GetMemberBinder binder,
out object result)
public virtual bool TrySetMember(SetMemberBinder binder,
object value)
public virtual bool TryDeleteMember(DeleteMemberBinder binder)
public virtual bool TryConvert(ConvertBinder binder,
out object result)
public virtual bool TryUnaryOperation
(UnaryOperationBinder binder, out object result)
public virtual bool TryBinaryOperation
(BinaryOperationBinder binder, object arg,
out object result)
public virtual bool TryInvoke
(InvokeBinder binder, object[] args, out object result)
public virtual bool TryInvokeMember
(InvokeMemberBinder binder, object[] args,
out object result)
...
}
As you can see this class has methods to override things like what happens when a property is access or a method is invoked. A detailed description of this class is available from the Getting Started with the DLR as a Library Author document .
The FSDynJObjectWrapper
class
As presented above the
FSDynJObjectWrapper
inherits from DynamicObject
and provides the required functionality. For this example the class is implemented using F# (although any .NET language could be used) and looks like this:
open System.Dynamic
open System.Reflection
open System.Linq.Expressions
open Newtonsoft.Json.Linq
open Newtonsoft.Json
type FSDynJObjectWrapper(theObject:JObject) =
inherit DynamicObject() with
override this.TryGetMember(binder : GetMemberBinder, result : obj byref ) =
match theObject.[binder.Name] with
| null -> false
| :? JObject as aJObject ->
result <- FSDynJObjectWrapper(aJObject)
true
| theValue ->
result <- theValue
true
The
TryGetMember
will be called when accessing a property. It tries to lookup the name of the requested property in the JObject
instance. A new instance of the wrapper is created if the property value is another JObject
instance allowing expressions like: aObj.user.screen_name
.For the next posts I'm going to show the use of other DLR classes and examples using other DLR languages.
Code for this post can be found here.