Techno Fattie

Josh Carroll

The other day an interesting question was posed on Stackoverflow. Sumarizing:
"How can I add methods to a type dynamically at runtime and have them be available to all other instances of that type?"
That is certainly an interesting question. Of course this is similar to how JavaScript works via the prototype property that all objects have. So I set out to see how easy it would be to simulate prototypal inheritance in C# using the new Dynamic Language Runtime features introduced in C# 4.0.

Now let me preface this by saying this solution is an answer in search of a question. That is, there is no particular problem I can immediately think of that this solves. It is a decent demonstration of the dynamic capabilities available to you in C#, but if you find yourself needing this kind of behavior, you might be a closet hipster.

What would such an implementation look like? Imagine the following class structure:


public class Foo {}
public class Bar: Foo {}


And now we would like to be able to dynamically define methods for Foo and Bar at runtime like so.


var foo1 = new Foo();
var foo2 = new Foo();

Foo.Add = new Func<Int32,Int32,Int32>((a, b) =>; a + b);

var result1 = foo1.Add(5, 5); // result1 == 10
var result2 = foo2.Add(10, 5); // result2 == 15


As it is written, this is impossible since it won't even compile. However, if we leverage the DLR and the dynamic keyword, then we can begin to make some magic happen. ExpandoObject is certainly an attractive new addition to .Net, as it allows us to dynamically add members at runtime, but they are local to that instance only. So for our purposes we are going to have to turn to the low level DynamicObject. DynamicObject gives us hooks into the new dynamic features of the runtime, but we are forced to write all the necessary plumbing to get the functionality we want. At a minimum we need to be able to:
  • Add new properties
  • Add new methods
  • Retrieve the value of dynamic properties
  • Invoke dynamically added methods
This turns out to be pretty easy by overriding just three methods from DynamicObject. TrySetMember, TryGetMember and TryInvokeMember.

public class ProtoObject : DynamicObject
{
private Dictionary<String,Object> _members = new Dictionary<String,Object>();

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
Object member = null;
result = null;

//Check to see if we have a member of this name
var success = _members.TryGetValue(binder.Name, out member);

//Check to make sure it is a delegate that can be invoked
if (success && member is Delegate)
{
//Execute the member with the passed in arguments and assing the result
result = ((Delegate)member).DynamicInvoke(args);
}

return success;
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
//Attempt to get the saved value with specified name
var success = _members.TryGetValue(binder.Name, out result);

return success;
}

public override bool TrySetMember(SetMemberBinder binder, object value)
{
//Add the new member name and value to our dictionary
// or override the existing value
if (_members.ContainsKey(binder.Name))
_members[binder.Name] = value;
else
_members.Add(binder.Name, value);

return true;
}
}


Now we have a custom object that will act similar to how ExpandoObject works. However, we still haven't solved the issue of inheriting members across all types. What we need is a shared collection of members that are specific to that type.
 
I've chosen a static Dictionary<Type,ExpandoObject> for this solution. Obviously we want to use Type as a key since the members should be specific to a type, and ExpandoObject already gives us all the functionality we need to store a collection of arbitrary properties and methods.

In order to make this work properly, we need to initialize the Dictionary with each new type in the inheritance chain, and provide a humane way of adding new members to a specific type. The constructor can be used to ensure that new types are added to the Dictionary, and by getting creating with the dynamic keyword, we can add a Prototype property that will give each type access to it's corresponding ExpandoObject.

private static readonly Dictionary<Type,ExpandoObject> _prototypes = new Dictionary<Type,ExpandoObject>();

public ProtoObject()
{
if (Prototype == null)
{
_prototypes.Add(GetType(), new ExpandoObject());
}
}

public dynamic Prototype
{
get
{
if (_prototypes.ContainsKey(GetType()))
return _prototypes[GetType()];
else
return null;
}
}


Finally, when a request for a member is made, we need to first check to see if there is one defined on the instance. If we can't find one, then we can begin looking for a matching member in the prototype object, walking the inheritance chain until we find what we are looking for.

Since finding an appropriate prototype member by walking the inheritance chain is recursive in nature, a helper method can be added to make this easier. While TrySetMember remains unchanged, TryInvokeMember and TryGetMember need to change slightly to accommodate the new functionality, but not by much.

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
Object member = null;
result = null;

var success _members.TryGetValue(binder.Name, out member);

if (success && member is Delegate)
{
result = ((Delegate)member).DynamicInvoke(args);
}

if (!success)
{
member = FindPrototypeMember(binder.Name, GetType());

if (member is Delegate)
{
result = ((Delegate)member).DynamicInvoke(args);
success = true;
}
}

return success;
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var success = _members.TryGetValue(binder.Name, out result);

if (!success)
{
var member = FindPrototypeMember(binder.Name, GetType());

if (member != null)
{
result = member;
success = true;
}
}

return success;
}

//Walk the inheritance chain using recursion to find a suitable
// prototype member
private object FindPrototypeMember(string memberName, Type type)
{
if (String.IsNullOrWhiteSpace(memberName) || type == null) return null;

if (!_prototypes.ContainsKey(type)) return null;

var prototype = _prototypes[type] as IDictionary;

if (prototype.ContainsKey(memberName))
return prototype[memberName];
else
return FindPrototypeMember(memberName, type.BaseType);
}


Putting this all together allows us to inherit from this object and dynamically add members and properties at runtime that will be available to all instances of that type. In other words, given this class structure:

public class Foo: ProtoObject {}
public class Bar: Foo {}


This code is totally valid:

dynamic myFoo = new Foo();
dynamic yourFoo = new Foo();
dynamic myBar = new Bar();

myFoo.Prototype.Name = "Josh";
myFoo.Prototype.SayHello = new Action(s => Console.WriteLine("Hello, " + s));

yourFoo.SayHello(myBar.Name); // 'Hello, Josh'


Again, I can't think of any practical use for this off the top of my head, but it is interesting to see just how much flexibility you can squeeze out of C# with very little code. 

For those who are interested a more robust version of this code is available on GitHub. The unit tests are the best documentation of the additional features, mainly:
  • Ability to check for "undefined" members by returning a special value instead of throwing an exception
  • Ability to access the current instance from within dynamically added methods.
  • Allows original exception with full stack trace to propogate instead of a RuntimeBinderException.
comments powered by Disqus