Dynamic C# & DLR (Part V): Creating Custom Dynamic Types

Intro

In this article I´ll try to show an easy way of building a custom dynamic type; this which can be useful when dealing with non-static data structures which will be know only at runtime, not at compile type (like Asp.Mvc ViewBag property). Second reason for custom dynamic types is interoperability: creating custom dynamic classes can mean define bridges between C# and other languages like Python or Ruby. Custom dynamic classes can also help to improve code readability at large code bases, which become an item to count with from architecture point of view. Let´s see the steps to be done for building a simple custom dynamic type:

Custom Dynamic Types: Overview

Dynamic typing is not a standard feature, it´s not based on simple method patterns as statically typing, but it´s possible we can intercept DLR operations if we create our custom dynamic types. First approach for building dynamic types seems to point to IDynamicMetaObjectProvider interface; this is in fact, a very specialized interfaces and try to build types from here can be a complex task. In order to make things simpler Microsoft provides DynamicObject type, which implements the IDynamicMetaObjectProvider interface and it´s a perfect base class for implementing types with dynamic binding.

MSDN refers to DynamicObject class in the following way:

“The DynamicObject class enables you to define which operations can be performed on dynamic objects and how to perform those operations. For example, you can define what happens when you try to get or set an object property, call a method, or perform standard mathematical operations such as addition and multiplication”

C# Creating Dynamic Types 1
C# Creating Dynamic Types 1

So, in order to implement a custom dynamic type basis on DynamicObject class we will need to override some base class virtual methods for intercepting DLR operations.

TryInvokeMember for intercepting calling a method
TryGetMember For intercepting get property
TrySetMember For intercepting set property
TryCreateInstance For intercepting creating new instance
TryDeleteIndex For intercepting deleting index
TryGetIndex Etc…
TrySetIndex
TryUnaryOperation
TryBinaryOperation
TryConvert
TryInvoke

So, let´s provide a basic sample of dynamic type in order to explore some possibilities

MyDynamicType: TryGetMember, TrySetMember method

Let´s create a basic MyDynamicType class that needs to inherit from DynamicObject. We will create a private variable of Dictionary<string, object> for storing each class member. In order to enable access to properties getter and setters we need to override TryGetMember and TrySetMember methods, something similar to:

public class MyDynamicType : DynamicObject 
    {
 
        private Dictionary<string, object> _properties = new Dictionary<string, object>();
 
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return _properties.TryGetValue(binder.Name, out result);
        }
 
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            _properties[binder.Name] = value;
            return true;
        }

MyDynamicType: GetDynamicMemberNames

In order to enhance debugging capabilities it will be needed to provide GetDynamicMemberNames implementation, this method returns a complete list of all methods that have been dynamically added enabling visual studio to access this information during debugging:

public override IEnumerable<string> GetDynamicMemberNames()
        {
            return _properties.Keys;
        }
 
        public int Count()
        {
            return _properties.Count;
        }

In addition we include additional Count() method which returns the count of all members.

MyDynamicType: TryInvokeMember

Finally we will implement the TryInvokeMember method for intercepting all method calls over dynamic type. In this case we are going to override ToString() method for providing a string containing the collection of property-values, then we implement the TryInvokeMember method in which we intercept potential method calls to our dynamic type for providing ToString() custom logic when Flatten method is invoked. Something similar to:

public override bool TryInvokeMember(InvokeMemberBinder binder,object[] args,out object result)
        {
            if (binder.Name == "Flatten")
            {
                result = ToString();
                return true;
            }
            else
            {
                result = null;
                return false;
            }
        }
 
        public override string ToString()
        {
            var target = new StringBuilder();
 
            try
            {
                foreach (KeyValuePair<string, object> prop in _properties)
                    target.Append($"{prop.Key}={prop.Value}");
 
                return target.ToString();
            }
            catch(Exception ex)
            {
                // exception handling here
                return string.Empty;
            }
        }

Using new type

With this new dynamic type in place we can play a little bit:

static void Main(string[] args)
        {
            dynamic invoice = new MyDynamicType();
 
            invoice.Client = "Grounded Organic Coffee ";
            invoice.Address = "28 Jane St, New York, NY 10014 ";
            invoice.Tax = 14;
            invoice.Phone = "(212) 647-0943";
 
            Console.WriteLine(invoice.Flatten());
 
            Console.ReadLine();
        }

When we run this we can see that we can intercept calls to property setters:

C# Creating Dynamic Types 2
C# Creating Dynamic Types 2
C# Creating Dynamic Types 3
C# Creating Dynamic Types 3

In the same way we intercept Flatten() method call as we can see below:

C# Creating Dynamic Types 4
C# Creating Dynamic Types 4

We can see the results at console window:

C# Creating Dynamic Types 5
C# Creating Dynamic Types 5

In addition we can override the TryInvoke() method for providing no common C# way of calling method by directly invoking the object itself, something like

public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
        {
             result = ToString();
             return true;
        }

And rewrite the main method in the following way

static void Main(string[] args)
        {
            dynamic invoice = new MyDynamicType();
 
            invoice.Client = "Grounded Organic Coffee ";
            invoice.Address = "28 Jane St, New York, NY 10014 ";
            invoice.Tax = 14;
            invoice.Phone = "(212) 647-0943";
 
            Console.WriteLine(invoice());
 
            Console.ReadLine();
        }

If we run this:

C# Creating Dynamic Types 6
C# Creating Dynamic Types 6

And the result is the same

C# Creating Dynamic Types 5
C# Creating Dynamic Types 5

That´s all by now

See you on the road!