Introduction
Riddle: When is an object not an object? When it is a dynamic object. Well, not really. Dynamic objects are a mechanism for mapping class-like object behavior and binding at runtime. The short of it is that you have something you want to treat like an instance of a pre-defined class without having the pre-defined class, just the data.
The first scenario that comes to mind is legacy type data. Suppose you have some text data representing legacy data. Further suppose that the text data contains name and value pairs. In the past you would have to sift through the data, map a custom class to the names, and then parse the data populating the custom objects. Well, dynamic objects sort of let you define the mapping scenario without necessarily defining the custom class. Instead you define a child class that inherits from System.Dynamic.DynamicObject
and write code that describes how to make sense of the data. Then, you treat instances of the dynamic objects as if they were the instances of the (non-existent) custom class using member of (.) syntax.
The underlying data can be something is simple as a string, a text file, or an XML file. The result is that your write code like object.member
and the DynamicObject plumbing binds the member name dynamically (or, at runtime, if you will).
Defining a Simple DynamicObject
To define a DynamicObject in VB define a new class that inherits from System.Dynamic.DynamicObject. Override
one of the many available members based on how or what you want to invoke at runtime. For instance override TryGetMember
to get member properties. TryGetMember
accepts a GetMemberBinder
parameter, a ByRef
result that represents the return data, and returns a Boolean indicating success or failure. Listing 1 contains a DynamicObject, SimpleObject that overrides TryGetMember
and looks for GetBinderMember.Name
values of Name, Street, City_State.
Public Class SimpleObject
Inherits DynamicObjectProperty Data As String()
Public Sub New(ByVal Data() As String)
Me.Data = Data
End SubPublic Overrides Function TryGetMember(ByVal binder As GetMemberBinder,
ByRef result As Object) As BooleanDim item = (From one In Data
Where one.Contains(binder.Name)
Select one).First()
If binder.Name = “Name” Then
result = item.Replace(“Name: “, “”)
Return True
ElseIf binder.Name = “Street” Then
result = item.Replace(“Street: “, “”)
Return True
ElseIf binder.Name = “City_State” Then
result = item.Replace(“City_State: “, “”)
Return True
End If
Return False
End Function
End Class
Listing 1: SimpleObject is a DynamicObject that looks for simple string field values
SimpleObject
is initialized with an array of strings containing Name, Street, and City_State data. When an instance of SimpleObject
accesses a field at runtime, like SimpleObject.Name
, TryGetMember
will parse, find the correct string and parse out the “Name: ” part returning the data part.
Using a DynamicObject in VB
To use SimpleObject
think of it as any other kind of instance of a class. Initialize it with the correct parameters and invoke members as if they were early bound members. The DynamicObject plumbing will resolve the member access.
Listing 2 contains all of the code for the sample. The Module demonstrates how to use SimpleObject
.
In the Listing there are two arrays of strings that we want to treat like objects. The Main function initializes two instances of SimpleObject
, one for each array of strings. All that is left to do is access the data using member-of (.) syntax. For example, the SimpleObject
paul can access Name, Street, and City_State using the same syntax as if there were properties with these names.
Imports System.DynamicPublic Class SimpleObject
Inherits DynamicObjectProperty Data As String()
Public Sub New(ByVal Data() As String)
Me.Data = Data
End SubPublic Overrides Function TryGetMember(ByVal binder As GetMemberBinder,
ByRef result As Object) As BooleanDim item = (From one In Data
Where one.Contains(binder.Name)
Select one).First()
If binder.Name = “Name” Then
result = item.Replace(“Name: “, “”)
Return True
ElseIf binder.Name = “Street” Then
result = item.Replace(“Street: “, “”)
Return True
ElseIf binder.Name = “City_State” Then
result = item.Replace(“City_State: “, “”)
Return True
End If
Return False
End Function
End ClassModule Module1
Dim data() As String =
{“Name: Paul Kimmel”,
“Street: 1313 Mockingbord Ln.”,
“City_State: Flostinspace. MI 55555”}Dim data2() As String =
{“Name: Joe Kunk”,
“Street: 1313 Stargazer Way”,
“City_State: Flostinspace. MI 55555”
}Sub Main()
Dim paul As Object = New SimpleObject(data)
Console.WriteLine(paul.Name)
Console.WriteLine(paul.Street)
Console.WriteLine(paul.City_State)Dim joe As Object = New SimpleObject(data2)
Console.WriteLine(joe.Name)
Console.WriteLine(joe.Street)
Console.WriteLine(joe.City_State)
Console.ReadLine()
End Sub
End Module
Listing 2: Initialize SimpleObject with an array of strings but treat it (in this case) as if it had pre-defined Name, Street, and City_State properties.
Summary
Historically when programmers encountered legacy data, strings or XML some kind of code had to be written to parse and populate that data into custom objects. You can still do that of course. You also have the option to use LINQ to XML and a project-select clause-to access the data or you can use DynamicObjects in VS2010.
A DynamicObject uses late binding to let you treat data elements as fully qualified members of a class. There is no mapped class just mapping behaviors if you will. It will be interesting to see how DynamicObjects and late binding make their way into the lexicon of programming techniques.