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.



About the Author

Bipin Joshi

Bipin Joshi is a blogger and writes about apparently unrelated topics - Yoga & technology! A former Software Consultant by profession, Bipin has been programming since 1995 and has been working with the .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. He was a well known technology author, trainer and an active member of Microsoft developer community before he decided to take a backseat from the mainstream IT circle and dedicate himself completely to spiritual path. Having embraced Yoga way of life he now codes for fun and writes on his blogs. He can also be reached there.

Related Articles

Downloads

Comments

  • King

    Posted by Jay Braude on 07/04/2012 10:00am

    Nice and clear! I have a a dll that defines custom attributes. Cab I associate custom attributes wit the dynamic type?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • QA teams don't have time to test everything yet they can't afford to ship buggy code. Learn how Coverity can help organizations shrink their testing cycles and reduce regression risk by focusing their manual and automated testing based on the impact of change.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds