Using DynamicObject and ExpandoObject

Introduction

C#
is primarily a statically typed language. That means the compiler needs to know
in advance about the data type of a variable. In the absence of this
information, the compiler will throw a compilation error and will refuse to
compile the code. In spite of the advantages offered by the statically typed languages,
dynamic languages have their own place in application development. For example,
most of the web sites developed today make use of JavaScript in some way or the
other. Languages such as Python and Ruby are also popular amongst developers.
The C# language now supports dynamic features through Dynamic Language
Runtime (DLR)
. Part of these features include dynamic types, DynamicObject
Class
and ExpandoObject
Class
. This article explains these features and provides examples
illustrating how these features are used.

Note:
DLR functionality in .NET
4.0 is encapsulated in the System.Dynamic namespace. Ensure that in the example
that follows you have imported this namespace in the class files.

Understanding the Dynamic Data Type

The C# compiler expects that you clearly specify the data
type of a variable before you compile the code. In other words it enforces
compile time type checking on your code. Though this works great for most of cases,
at times you may want to bypass this compile time checking. Consider for
example, that you wish to execute JavaScript stored in an external file and you
want to exchange variables between your C# code and JavaScript code. In such
cases, your C# code cannot detect the data types used in the script at compile
time and you must skip the type checking. Considering such needs C# introduced
the dynamic type. A dynamic type allows you to skip compile time type checking.
Only at runtime when the code is actually executed, errors (if any) will be
generated.

In order to understand how the dynamic type works, let’s
develop a simple Console Application and use dynamic variables. Begin by
creating a new Console Application and then add the following code in the
Main() method.

static void Main(string[] args)
{
    dynamic d;

    d = 100;
    Console.WriteLine(d + " - " + d.GetType());

    d = "Hello World!";
    Console.WriteLine(d + " - " + d.GetType());

    Console.ReadLine();
}

The above code declares a variable (d) of type dynamic. The
variable is then assigned an integer value (100) and the data type is outputted
on the console window. Next, the same variable d is now assigned a string value
and again its data type is outputted. The following figure shows a sample run
of the application.

Sample run of the Console application
Figure 1: Sample run of the Console application

Notice the above figure carefully. The first line shows that
d is an integer type whereas the second line shows that d is a string. This
means that a dynamic variable can change its data type at runtime. If you try
to perform invalid operations on the data (using string manipulation functions
on an integer or using mathematical functions on a string for example) then an
error will be generated at runtime.

Difference Between var and Dynamic Types

At first glance you may find the dynamic type is the same as
variables of the var type. However, they are not the same. When you use a var
keyword (say in a LINQ query) the data type is detected in a delayed fashion
but once a variable is assigned a value the data type is fixed. It cannot be
changed later. In the case of dynamic types, however, the data type can change
multiple times during the execution of the application. As long as the
operation under consideration is valid the runtime won’t have any problem in
dealing with a dynamic variable. Just to explain this difference, consider the
following fragment of code:

 string[] strMonths = { "Jan", "Feb", "Mar"};
int[] numMonths = { 1, 2, 3 };

//OK because it is first assignment
var varMonths = from m in strMonths
                select m;

//ERROR because varMonths is already a collection of strings
//and now cannot take integers
varMonths = from m in numMonths
            select m;

As you can see above, var cannot change its data type once
assigned whereas dynamic variable can change its data type as we did in the
previous example.

Understanding Dynamic Objects

Normally when you wish to use some object in your code, you
first need to create a class and write properties and methods in it. You can
then create objects of that class, set their properties and invoke methods on
them. At times, however, you may want to create objects and set their
properties dynamically. That means you won’t have a class against which the
compiler can validate your property assignments or method calls. Why is something
like this ever needed? Consider that you are exchanging data between an
external script and C#. Now your C# code won’t be aware of the objects exposed
by the script at compile time for obvious reasons. So in your C# code you will
be assigning properties and invoking methods without knowing if they really
exist. Errors, if any, will be raised only at runtime.

One example of such a dynamic object can be found in ASP.NET MVC 3. Consider the
following piece of code written in a controller class:

ViewBag.StatusMessage = "Data saved successfully!";
ViewBag.StatusCode = "100";
ViewBag.LogDate = DateTime.Now;

ASP.NET MVC 3 provides a ViewBag object that allows you to
store arbitrary values that you wish to pass to the View. As illustrated in the
above example, you simply set properties on the ViewBag object as if they are coded
in the ViewBag object itself. In reality, ViewBag doesn’t contain any property
definitions for StatusMessage, StatusCode and LogDate (these names are
developer defined and you can use any valid name there). In other words, you
added properties dynamically to the ViewBag object.

The System.Dynamic namespaces provides two classes that
allow you to create your own dynamic objects. They are – DynamicObject and
ExpandoObject. both of which implement the IDynamicMetaObjectProvider
interface. The IDynamicMetaObjectProvider interface allows you to bind
operations to the underlying object at runtime. In the following sections you
will learn how to make use of DynamicObject class as well as ExpandoObject
class.

DynamicObject Class

In order to create your own dynamic object using
DynamicObject class you need to inherit it from DynamicObject and override
three methods, viz. TryGetMember, TrySetMember and TryInvokeMember. The first
two methods allow you to get and set dynamic properties whereas the last method
allows you to invoke method calls on the dynamic object. In order to understand
how these three methods can be used let’s create a dynamic object – Employee.

Add a new class to the Console Application you created
earlier and key the following code into it:

public class Employee : DynamicObject
{

    Dictionary<string, object> properties = new Dictionary<string, object>();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (properties.ContainsKey(binder.Name))
        {
            result = properties[binder.Name];
            return true;
        }
        else
        {
            result = "Invalid Property!";
            return false;
        }
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        properties[binder.Name] = value;
        return true;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        dynamic method = properties[binder.Name];
        result = method(args[0].ToString(), args[1].ToString());
        return true;
    }
}

As you can see the Employee class inherits from the
DynamicObject base class and then overrides the TryGetMember, TrySetMember and
TryInvokeMember methods. The TryGetMember() method returns a boolean value
indicating whether the operation was successful or not. The actual property
value is retrieved via the results output parameter. The property values are
stored in a dictionary (properties). You then check whether the property whose
value is to be retrieved (binder.Name) exists in the dictionary. Accordingly,
result output parameter is set and true / false is returned.

The TrySetMember() method simply stores a property and its
value in the dictionary and returns true. If you wish to restrict property
names or values based on certain criteria you will add that logic here and
return true / false accordingly. In our case we don’t have any such restriction
and the code returns true.

The TryInvokeMember() method retrieves a reference to an
anonymous function (this will be clear in a moment) and invokes that function
by passing the required parameters.

Once you complete the Employee class, modify the Main()
method to include the following lines of code:

d = new Employee();
d.FirstName = "Tom";
d.LastName = "Jerry";
d.BirthDate = new DateTime(1960, 12, 01);

Func<string, string, string> method = (a, b) => a + " " + b;

d.GetData = method;
Console.WriteLine(d.FirstName + " " + d.LastName + "..." + d.GetData("Tom", "Jerry") + " - " + d.GetType());

The above code assigns a new instance of Employee class to
the dynamic variable (d). It then sets three properties on the dynamic object
viz. FirstName, LastName and BirthDate. Notice that Employee class nowhere
defines these properties and you are setting them dynamically. The code then
creates an anonymous method that simply concatenates and returns the two
parameters passed to it. The GetData dynamic method is then set to point to this
anonymous method. Finally, FirstName, LastName values are outputted along with
a call to GetData() dynamic method. The following figure shows a sample run of
the above code:

Sample run a new instance of Employee class to the dynamic
Figure 2: Sample run a new instance of Employee class to the dynamic
variable

ExpandoObject Class

In the case of the DynamicObject class, you need to do more
work by inheriting and overriding certain methods. In the process you get more
control on how the resultant dynamic object should behave. The ExpandoObject
class is a sealed class, which means you cannot inherit it further. It provides
a simpler implementation of a dynamic object ready for you to consume in your
applications without much work. The same code that we used in the preceding
example can be written using ExpandoObject as follows:

d = new ExpandoObject();
d.FirstName = "Tom";
d.LastName = "Jerry";
d.BirthDate = new DateTime(1960, 12, 01);

Func<string, string, string> method2 = (a, b) => a + " " + b;

d.GetData = method2;
Console.WriteLine(d.FirstName + " " + d.LastName + "..." + d.GetData("Tom", "Jerry") + " - " + d.GetType());

Notice that the above code creates an instance of
ExpandoObject and sets properties on it as before.

An instance of ExpandoObject with properties
Figure 3: An instance of ExpandoObject with properties

Summary

The dynamic type allows you to write code that bypasses
compile time type checking. A variable of dynamic type can point to different
types at runtime. You can create your own dynamic objects using DynamicObject
and ExpandoObject classes. In order to use the DynamicObject class you need to
create a class that inherits from DynamicObject class and then override
TryGetMember, TrySetMember and TryInvokeMember methods. This approach gives you
precise control on the properties and methods the dynamic object can have. On
the other hand ExpandoObject provides a simple ready to use implementation of a
dynamic object. Using these features. you can create dynamic objects that allow
you to add properties and methods to them dynamically.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read