Fun with C# dynamics

A brief introduction to C# 4's dynamic keyword, and the fun that can be had with it.


C# 4 added the dynamic type, allowing developers to bypass compile-time type checking. This functionality was originally intended to assist with the consumption of COM APIs as well as dynamic APIs (such as IronPython, IronRuby, etc.)

However, in the time since release, lots of interesting stuff has been done with dynamic:

Dapper can return dynamic objects that represent rows of a SQL query result set. This leads to some lightweight and elegant code:

string sql = "SELECT name, description, cost FROM products";
IEnumerable<dynamic> products = connection.Query(sql);
foreach (dynamic product in products)
{
    string name = product.name;
    string description = product.description;
    int cost = product.cost;
}

ImpromptuInterface can wrap a dynamic with a static interface. This lets you use dynamics in even more interesting places. The following (contrived) example demonstrates the basic usage, but it's obvious that this allows some much more interesting things:

interface IAdder
{
    int Add(int a, int b);
}

dynamic d = new ExpandoObject();
d.Add = new Func<int, int, int>((int x, int y) => x + y);
IAdder adder = Impromptu.ActLike<IAdder>(d);

There are plenty of other examples where dynamic is used to do interesting things in C#.

DynamicObject is probably the quickest and easiest way to get started; it provides a base class with a number of virtual methods that can be overridden to specify some custom functionality.

The following example is a clever bit of code I wrote to simplify the consumption of XML data. It extends DynamicObject, using the TryGetMember method to navigate the XML tree, and the TryConvert method to convert nodes into actual values:

class DynamicXml : DynamicObject
{
    public static DynamicXml Parse(string text)
    {
        return new DynamicXml(XElement.Parse(text));
    }

    private readonly XElement _root;

    private DynamicXml(XElement root)
    {
        _root = root;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        XElement[] nodes = _root.Elements(binder.Name).ToArray();
        if (nodes.Length > 1)
        {
            result = nodes.Select(o => new DynamicXml(o)).ToArray();
            return true;
        }
        else if (nodes.Length == 1)
        {
            result = new DynamicXml(nodes.First());
            return true;
        }
        else
        {
            result = null;
            return false;
        }
    }

    public override bool TryConvert(ConvertBinder binder, out object result)
    {
        try
        {
            result = Convert.ChangeType(_root.Value, binder.Type);
            return true;
        }
        catch (Exception ex)
        {
            if (ex is InvalidCastException ||
                ex is FormatException ||
                ex is OverflowException ||
                ex is ArgumentNullException)
            {
                result = null;
                return false;
            }
            else
            {
                throw;
            }
        }
    }
}

A complete copy of the above code (including XML documentation, etc.) is available on GitHub.

This allows us to consume XML data as follows:

string xml = "<Person><Name>Matt</Name><IsAwesome>true</IsAwesome></Person>";
dynamic person = DynamicXml.Parse(xml);
string name = person.Name; // returns 'Matt'
bool awesome = person.IsAwesome; // returns 'true'

It works with multiple levels of nesting, too.

I wouldn't necessarily recommend this code for use in production, but it serves as a nice example of the interesting things that can be done with C#'s dynamic support.


Posted by Matthew King on 9 February 2014
Permission is granted to use all code snippets under CC BY-SA 3.0 (just like StackOverflow), or the MIT license - your choice!