Click here to Skip to main content
Click here to Skip to main content

Dynamic Type Programming with C# 4.0

, 10 Nov 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
Learn how to define types without defining the class first using C# 4.0.

Background

To truly understand how to process the dynamic lookup calls, you must have a relatively advanced understanding of Expression Trees and how to visit them properly. The subject is beyond the scope of this article, but is crucial in understanding the nuances of processing such calls. Please refer to the MSDN text for further information about this.

Why Dynamic Programming

Examine the following listing:

function NewPerson(name, age) {
    var person = new Object();
    person.FullName = name;
    person.Age = age;
    person.Talk = function() 
    {
        alert("My name is " + name + " i am " + age + " years old");
    };
    return person
}

//same classification different interfaces 
var oke = NewPerson("oke", 4);
oke.RideBike = function() 
{
    alert("look daddy!");
};
var azuka = NewPerson("azuka", 2);
azuka.WearDiper = function() 
{
    alert("its good to be 2 ;-)");
};

Can this type of functionality be implemented in C# using the built-in features alone? Before you answer consider the following. The listing below depicts the classification of a Person and the creation of two instances of that class, oke and azuka. As can be seen above, each Person class has two public properties, Age and Name, which are set at construction time. Once created, the oke instance adds an additional method RideBike, while the azuka instance adds its own additional method WearDiper. To go back to the question, the answer is yes. Here is a C# equivalent:

public class Person 
{
    public int Age { get; set; }
    public string Name { get; set; }
    public void Talk()
    {
        Console.WriteLine("My name is " + Name + " i am " + 
                          Age + " years old");
    }
}

public class OkePerson : Person 
{
    public void RideBike()
    {
        Console.WriteLine("Look Daddy!");
    }
}

public class AzukaPerson 
{
    public void WearDiper()
    {
        Console.WriteLine("its good to be two ;-)");
    }
}

//in main 
OkePerson oke = new OkePerson();
AzukaPerson azuka = new AzukaPerson();

Of course, with each additional instance, with a unique behavior comes a new subtype that supports the behavior; each of which might not be ubiquitous enough to require its own type. There are several variations to this technique that all introduce the same unnecessary bloat. This is in fact one of the main problems with C#'s implementation of static types. As the name implies, static types are known at compile time, which in the case of C# means, must already be defined at compile time. This necessitates the construction of every possible type and behavior before compilation. When the objects are large with lots of state, behavior, and such, this is not such a bad thing, but when I need some silly one-off style object as a simple data container, or a slight mutation of a pre-existing object as with the example above, this can become relatively burdensome. In fact, I believe that such (relatively meaningless) types introduce an unnecessary complexity.

Enter LINQ, Lambdas, and Anonymous Types

I think the C# team realized this and made steps to help alleviate it with LINQ. By allowing the coder to create dynamic projections that could be encapsulated into the var type (through type inference), we are able to create all sorts of anonymous types without having to go somewhere and define them first in order to get everything to compile. Here is how it might look:

Action talk_method = () =>
{
    Console.WriteLine("Hi daddy!");
};
Action ride_bike = () =>
{
    Console.WriteLine("Look Daddy!");
};
Action wear_diper = () =>
{
    Console.WriteLine("It's good to be two ;-)");
};
var oke = new
{
    Name = "Oke",
    Age = 4,
    Talk = talk_method,
    RideBike = ride_bike,
};
var azuka = new
{
    Name = "Azuka",
    Age = 2,
    Talk = talk_method,
    WearDiper = wear_diper
};
oke.RideBike();
azuka.WearDiper();

To be clear, this is not really mutation; the anonymous types associated with the oke and azuka variables are completely different. So what is wrong with that? Nothing. But if you want behavior similar to the above sample, then LINQ falls short. Firstly, a problem with projections - and local type inference - as they relate to C# is that it is localized to a method. This is a marked disadvantage when attempting to expose your dynamic types beyond the scope of the method in which it was created. Since var cannot be used as a return type and the actual type of the projection is unknown, your projections must be converted to known types in order to use them elsewhere (more specifically, outside of the type providing method). This kind of makes this approach not very useful. There are ways around this however; for instance, we can return var as object in a Create method and use Reflection to get and set the values of Name and Age as well as to call the Talk function. Here is a sample of how that can be done.

public static object CreatePerson(string name, int age)
{
    Action talk_method = () =>
    {
        Console.WriteLine("Hi daddy!");
    };
    var oke = new
    {
        Name = name,
        Age = age,
        Talk = talk_method, 
    };
    return oke;
}
//in main
// Line 1> var oke = CreatePerson("oke", 4);
// Line 2> string name = (string)oke.GetType().GetProperty("Name").GetValue(oke, null);
// Line 3> 3 oke.GetType().GetProperty("Name").SetValue(oke, "Edward", null);

If you copy paste and run this sample, you will notice that you get a runtime error on the third line in the main segment of the code. This is when we try to set the value of the Name property of the Person object we created in line 1. This leads us to the second problem with the LINQ approach: LINQ based dynamic types are immutable, so the types I created are really nothing but data containers. This means that I can't change the value of Name or Age after the fact. Bummer! What's even worse than that is the fact that C# interface conversions are based on static type declaration as opposed to signature compliance. So although my anonymous type in variable t has a public Name property of type string, a public Age property of type int, and a public Talk property of type Action, I can't convert from one type to the other. I will continue to argue that there is no need for interface declarations in type definitions, but I suspect I'm the only audience.

The other main feature missing here is the instance level mutation that allows me to modify the classification of a type at runtime. In the JavaScript sample, the two persons object are created first, then additional individual behavior is applied to each one. The oke instance is given a RideBike method, and the azuka instance is given the WearDiper function. There is no built in functionality in C# to reproduce this feature, but there are patterns that can be applied to resolve this. Historically, this has been done in C# by using V-Tables to represent the dynamic context of the given instance. The listing below illustrates a possible representation of a simple v-table for holding arguments which take no arguments and return no values.

static Dictionary<object, Dictionary<string, Action>> global_vtable;

When coupled with the Extension Methods functionality of C# 3.0, the results can be quite spectacular. The listing below illustrates the use of this mechanism to achieve some semblance of dynamic programming:

//listing
public class DynamicFunctionContext<RETVAL>
{
    object _internal;
    Func<RETVAL> _function;
    string _function_name;
    public DynamicFunctionContext(object obj, string function_name)
    {
        _internal = obj;
        this._function_name = function_name;
    }
    public bool IsDefined
    {
        get
        {
            if (_function != null)
                return true;
            else
            {
                object prototype = _internal.GetPrototype();
                if (prototype != null)
                    return prototype.function<RETVAL>(_function_name).IsDefined;
                else
                    return false;
            }
        }
    }
    public Func<RETVAL> define
    {
        set
        {
            _function = value;
        }
    }
    public Func<RETVAL> call
    {
        get
        {
            if (_function != null)
                return _function;
            else
            {
                object prototype = _internal.GetPrototype();
                if (prototype != null)
                    return prototype.function<RETVAL>(_function_name).call ;
            }
            throw new MissingMethodException("The specified function has " + 
                      "not been defined for this instance");
        }
    }
}

public static class ObjectExtentions 
{
    internal static Dictionary<object, object> _prototype_list = 
             new Dictionary<object, object>();
    static Dictionary<object, FunctionDictionary> _context_list = 
           new Dictionary<object, FunctionDictionary>();
#region Prototype Management
public static void SetPrototype(this object instance, object prototype)
{
    if (_prototype_list.ContainsKey(instance))
    {
        _prototype_list[instance] = prototype;
    }
    else
    {
        _prototype_list.Add(instance, prototype);
    }
}
public static object GetPrototype(this object instance)
{
    object retval = null;
    if (_prototype_list.ContainsKey(instance))
    {
        retval = _prototype_list[instance];
    }
    return retval;
}
#endregion
#region Dynamic Function Context

public static DynamicFunctionContext<RETVAL> function<RETVAL>(this object instance, 
              string function_name)
{
    DynamicFunctionContext<RETVAL> ctx = null;
    if (_context_list.ContainsKey(instance))
    {
        Dictionary<string, object> temp = _context_list[instance];
        //string function_type_name = typeof(T).FullName; 
        if (temp.ContainsKey(function_name))
        {
            object context = temp[function_name];
            if (context is DynamicFunctionContext<RETVAL>)
                ctx = context as DynamicFunctionContext<RETVAL>;
            else
                throw new Exception("no function with this return type is defined");
        }
        else
        {
            ctx = new DynamicFunctionContext<RETVAL>(instance, function_name);
            temp.Add(function_name, ctx);
        }
    }
    else
    {
        //if a context for this instance has not been created then create one 
        ctx = new DynamicFunctionContext<RETVAL>(instance, function_name);
        FunctionDictionary temp = new FunctionDictionary();
        temp.Add(function_name, ctx);
        _context_list.Add(instance, temp);
    }
    return ctx;
}
#endregion
#region Internal Types
    public class FunctionDictionary : Dictionary<string, object> { }
#endregion
}

The listing above is an excerpt from the downloadable code. It expands on the idea of using a Dictionary to store a list of functions keyed by the object instance. This functionality should mimic the ability to mutate object instances from each other at runtime. The result of this is that CreatePerson can now be defined like this:

public static object CreatePerson2(string name, int age)
{
    var person = new Person 
    {
        Name = name,
        Age = age,
    };
    return person;
}

And each instance of the created type can be mutated as follows:

var oke = CreatePerson2("oke", 4);
oke.function<bool>("RideBike").define = () =>
{
    Console.WriteLine("Look Daddy!");
    return true;
};
var azuka = CreatePerson2("azuka", 2);
azuka.function<bool>("WearDiper").define = () =>
{
    Console.WriteLine("Its good to be 2!");
    return true;
};

Enter C# 4.0

C# 4.0 introduces the dynamic keyword and the ability to defer resolution of a given type's member till runtime. Wouldn't it be great if we could mimic the syntax from JavaScript exactly and do something like the listing below?

dynamic person = new object();
person.Name = name;
person.Age = age;

In the example above, the Person instance of type object has been mutated with a Name and Age property. Now I am sure there are a lot of cool uses of the whole dynamic thing outside of the framework; for instance, when interacting with unmanaged COM types, it comes in pretty handy, but when the underlying type is a managed type, then the basic usage of dynamic is just a handy dandy way to express standard Reflection. The great thing about this when it comes to the previously discussed Lambdas is that Reflection need no longer be overtly expressed in order to access a desired member. If we were to change our first definition of CreatePerson to the following:

public static dynamic CreatePerson(string name, int age)
{
    Action talk_method = () =>
    {
        Console.WriteLine("Hi daddy!");
    };
    var oke = new
    {
        Name = name,
        Age = age,
        Talk = talk_method, 
    };
    return oke;
}

We could access Name, Age, or Talk as follows:

dynamic oke = CreatePerson("oke", 4);
string str = oke.Name;

Internally, the following is still being done:

oke.GetType().GetProperty("Name").GetValue(oke, null);

However, since using Reflection ultimately means having a previously defined type to reflect upon, this base implementation is relatively useless in helping us define dynamic types from scratch. This means that the example above which attempted to mutate object with two additional properties will fail at runtime since the underlying type object does not have those properties defined in it. Fortunately, dynamic also provides the IDynamicObject interface for those of us who want to do our own dynamic dispatching. How this works is beyond the scope of this already long article, but to summarize, it allows you to intercept the calls made at runtime by the framework to resolve invocations made on a given dynamic type and literally do what you want. Let's explore this step by step so it's clear what we mean here. We already know that instead of doing something like this:

object obj = new object();
obj.ToString();

you can use the dynamic types and do this:

dynamic obj = new object();
obj.ToString();

In the first instance, ToString is validated at compile time. If the function does not exist in the exact signature that it is being called with, your code will not compile. In the second example, ToString is ignored at compile time. Whether or not the function exists, the code will compile. At runtime, when the symbol ToString associated with the instance obj of type object is encountered, the runtime will attempt to evaluate it (in the case of object using reflection). When the type of the dynamic is a type which implements IDynamicObject, it will use that type's implementation of IDynamicObject to evaluate the symbol. This is a very powerful feature. In the context of our discussion, I mean that we can do what JavaScript already does and add members to types at runtime!

The implementation of this requires a number of things. First, we must define a type to implement IDynamicObject. The listing below defines a new type DynamicObject which is a concrete implementation of IDynamicObject.

public class DynamicObject : IDynamicObject
{
    DynamicObjectMeta _metadata;
    ~DynamicObject()
    {
        DynamicObjectMeta._internal_data.Remove(this);
    }
    public MetaObject GetMetaObject(System.Linq.Expressions.Expression parameter)
    {
        return new DynamicObjectMeta(parameter, this);
    }
}

As you can see, the dynamic object itself has nothing special defined; besides returning a new instance of a type DynamicObjectMeta, and removing itself from a static Dictionary within the DynamicObjectMeta type, it is pretty barren. In fact, all the work of faking out the runtime happens in the DynamicObjectMeta type, and most of it is essentially the same as the v-table approach we followed earlier. Again, for the instance level mutation to work, every instance must be uniquely represented in a dictionary which holds as its values, a dictionary of members associated with the given type. Here is a sample of how this can be done.

public class DynamicObjectMeta : MetaObject
{
    internal static Dictionary<object,Dictionary<string, object>> _internal_data = 
                    new Dictionary<object,Dictionary<string, object>>();

    public DynamicObjectMeta(System.Linq.Expressions.Expression expression, 
                             DynamicObject test) : base(expression,Restrictions.Empty,test)
    { 
    }

    public override MetaObject SetMember(SetMemberAction action, MetaObject[] args)
    {
        object key = args[0].Value;
        if (_internal_data.ContainsKey(args[0].Value))
        {
            if (_internal_data[args[0].Value].ContainsKey(action.Name))
            {
                _internal_data[args[0].Value][action.Name] = args[0].Value;
            }
            else
            {
                _internal_data[args[0].Value].Add(action.Name, args[1].Value);
            }
        }
        else
        {
            _internal_data.Add(args[0].Value, new Dictionary<string, object>());
            _internal_data[args[0].Value].Add(action.Name, args[1].Value);
        }
        return this;
    }

    public override MetaObject GetMember(GetMemberAction action, MetaObject[] args)
    {
        MetaObject obj = new MetaObject(Expression.Constant(null), Restrictions.Empty);
        if (_internal_data.ContainsKey(args[0].Value))
        {
            if (_internal_data[args[0].Value].ContainsKey(action.Name))
            {
                obj = new MetaObject(Expression.Constant(
                      _internal_data[args[0].Value][action.Name]), 
                      Restrictions.Empty);
                return obj;
            }
        }
        return obj;
    }
}

DynamicObjectMeta inherits from MetaObject, which provides the mechanism for intercepting the call resolution. In the sample above, I have overridden just two of the many possible virtual functions it provides, GetMember and SetMember. SetMember is called whenever a value is set to a member that needs resolution. GetMember is called whenever a value needs to be retrieved from a member that needs resolution. We all know at this point that a public property Hello is not defined on DynamicObject, so let us go ahead and see what happens when we run something like the following:

dynamic test = new DynamicObject();
test.Hello = "this is a test";

This will call the SetMember function, passing Hello as the SetMemberAction value, object instance test as the MetaObject in index 0 of the MetaObject array, and the string "this is a test" as the MetaObject in index 1 of the MetaObject array. This implementation simply takes those values and stores them in a static dictionary keyed on that object instance.

Any call to retrieve the value stored in test.Hello will automatically call the GetMember method which simply reads that value from the Dictionary (given the instance and method which are passed in exactly the same way). Here is how the creation and usage of the dynamic types will work once this approach is employed:

public static dynamic CreatePerson(string name, int age)
{
    Action talk_method = () =>
    {
        Console.WriteLine("my name is {0}, I am {1} year(s) old ",name, age);
    };
    dynamic person = new DynamicObject();
    person.Name = name;
    person.Age = age;
    person.Talk = talk_method;
    return person;
}

As you can see from the above example, the methods and properties of Person are applied completely dynamically. Neither Name and Age nor Talk is part of the classification of the type. In fact, we have created a new Person type from the generic DynamicObject. Below is a listing to illustrate how this new person type can be mutated after creation.

dynamic oke = CreatePerson("oke", 4);
Action ride_bike_function = () =>
{
    Console.WriteLine("Look Daddy!");
};
oke.RideBike = ride_bike_function;
Console.WriteLine("{0}\n{1}", oke.Name, oke.Age);
oke.Talk.Invoke();
dynamic azuka = CreatePerson("azuka", 2);
Action wear_diper_function = () =>
{
    Console.WriteLine("It's good to be 2!");
};
azuka.WearDiper = wear_diper_function;
oke.RideBike.Invoke();
oke = null;
azuka.WearDiper.Invoke();

Just like in the JavaScript sample, the oke instance of Person has been mutated with a RideBike function, while the azuka instance has been mutated with a WearDiper. Both instances share talk, but have distinct unique defined behavior in their respective extra methods.

Conclusion

The infrastructure introduced in C# 4.0 to support dynamic types is quite robust. This article only begins to scratch the surface on what can be done with it. If you are interested in learning more, I suggest getting intimate with the inner workings of expression trees as they are crucial in processing dynamic calls. The samples above are rudimentary in nature. They neither fully utilize the appropriate feature set nor provide all the necessary checks and balances associated with building stable, well tested code. Please do not copy and paste them into any work verbatim, without further enhancements on your part to stabilize everything. Fair warning!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Edward Moemeka

United States United States
Hi I'm Edward Moemeka,
For more interesting articles about stuff check out my blog at http://moemeka.blogspot.com
To correspond, email me at edward.moemeka@synertry.com
To support my company, thus help me feed my family, check out our awesome online preview at www.synertry.com. Remember, its in alpha Wink | ;-)

Comments and Discussions

 
GeneralNeed to be aware that "Dynamic Programming" has another long standing meaning PinmemberGlynn11-Nov-08 0:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 10 Nov 2008
Article Copyright 2008 by Edward Moemeka
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid