Thursday, January 27, 2011

Messing around with C# dynamic

At last night’s ALT.NET Vancouver meet up we were talking about the dynamic keyword in C# 4.0 and how it could be used for dispatching a message to the appropriate message handler.  The conversation with a look at Chris Nicola’s blog post on the topic.

The first test that he shows in the post fails. 

[Test]
public void cant_pass_base_class_to_function_dynamically()
{
dynamic handler = new FooMessageHandler();
IMessage message = new FooMessage();
handler.Handle(message);
}

To me, this was expected.  Despite using the dynamic keyword for the message handler, the C# compiler is still going to use the same algorithm for method matching as it does on a static object.  To make this method pass we need to add our own method matching, and in C# dynamic, that means overriding the TryInvokeMember method.


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

if (binder.Name == "Handle" && args.Length == 1 && args[0].GetType() == typeof(FooMessage))
{
Handle((FooMessage) args[0]);
return true;
}

return false;
}

This code looks to see if the Handle method was being called and then checks if the argument passed in will satisfy the real method then calls then method. It's not the cleanest code, but the test does pass with this override. We can take it a little further and move the method to the base class so that we don't have to repeat the override for each message handler.


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

if (binder.Name == "Handle" && args.Length == 1 && args[0].GetType() == typeof(T))
{
Handle((T)args[0]);
return true;
}

return false;
}

One of the conclusions that we reached at the meet up was that dynamic is well suited to where reflection would have been used.  I have done message dispatching with reflection in the past and I think I like this approach better once I clean up the code a little more.


P.S. Also check out Cliff Hammerschmidt’s post on Graft-on Visitor in C#.

No comments: