One of the things I’ve been doing a lot recently is trying to get some pretty dynamic behaviors out of a fairly strongly typed compile time language. That’s .NET 3.5 of course, and the Castle.DynamicProxy has been an invaluable ingredient.

The other day I saw some neat things like these and more David Ebbo was doing with dynamic in VS2010. Reading up on the new C# dynamic keyword and some interesting bits about IDynamicMetaObjectProvider, DynamicObject, and ExpandoObject to get up to speed - I started to wonder something about ways Castle DynamicProxy and C# dynamic could work together.

To set the stage - imagine some of the things you can do with your favorite dynamic language like Javascript, Ruby, and such. You can create an instance of class and add a method to the object, right? And the method you add can even hold a closure around variables and arguments when it was attached. You can also apply function and properties to classes to modify instance behaviors at runtime. Now with a normal CLR type you don’t get these kind of features on POCO types, of course, but if you combine DynamicProxy with a heavy use of virtual members there’s a whole lot you can do with interception.

Take the following for example.

public class Sample
{
  public virtual string Etc {get; set;}

  public virtual string HelloWorld(int x, string y)
  {
    return x + ":" + y + " " + Etc;
  }
}

And a place that compile-time CLR type is used.

public class SomeTypeOfWorker
{
  public void DoWork(Sample data)
  {
    Console.WriteLine(data.HelloWorld(42, "foo"));
  }
}

The gratuitous use of virtual enables us pass a dynamic proxy subclass for this object. As a proof of concept I made an object activator named MetaTypeEngine that wraps the base class in an interceptor and adds some dynamic support.

public class SomeCoordinator
{
  SomeTypeOfWorker _worker;

  public SomeCoordinator(SomeTypeOfWorker worker)
  {
    _worker = worker;
  }

  public void Example()
  {
    var engine = new MetaTypeEngine();
    dynamic sample = engine.New<Sample>();
    sample.HelloWorld = new Func<Sample, int, string, string>(
      (self, x, y) => self.Etc + "-" + x + y.Length );
    _worker.DoWork(sample);
  }
}

[Proof of concept MetaType.zip]

The T MetaTypeEngine.New<T>() method returns an instance of Sample proxy that intercepts all virtual functions and, if a lambda has been assigned as if it was a property, that lambda will be invoked before the interceptor proceeds to the base class implementation. The Sample proxy also provides an implementation of the IDynamicMetaObjectProvider interface to allow the instance to provide expressions to dynamic call sites. That’s why the dynamic sample.HelloWorld, used as a MemberSet, is stashing the lambda in a per-instance method dictionary instead of throwing a “HelloWorld function can’t be assigned like a property” exception.

Nifty, no?

The example’s not production code by a long shot. I personally guarantee anyone who really knows how to implement IDynamicMetaObjectProvider would facepalm if they saw it. But it shows the ingredients are all present to create a proper implementation of the concept.

Other tricks this example can do:

Overriding a virtual property with a lambda getter.

    sample.get_Etc = new Func<Sample, string>(self => "Replacement etc value");

Overriding at a type level. This assumes you’re using the same instance of the engine to instantiate and patching in your overrides at startup.

    engine.GetType<Sample>().SetMethod("HelloWorld", new Func<Sample, int, string, string>(
      (self, x, y) => self.Etc + "-" + x + y.Length ));

Implementing a missing method handler. This isn’t as helpful if you’re using the instance though a CLR typed variable (it’s just a compiler error then) but if you’re referencing the instance via dynamic it’s a simple way to project results for methods and properties that don’t really exist.

  sample.MissingMethod = new Func<Sample, MissingMethodCall, object>(
    (self, call) =>
    {
      if (call.Name == "get_Height") {return 320;}
      if (call.Name == "get_Width") {return 200;}
      return call.Default();
    });

MissingMethod can also be added at the pseudo-type level instead of the instance level.

engine.SetMissingMethod<Sample>((self,call)=> {return call.Default();});

Ah! Also it can be declared as a normal CLR method on the compiled type and would be invoked from a dynamic call to a method or property that doesn’t exist.

public class Sample
{
  public virtual string Etc {get; set;}

  public virtual string HelloWorld(int x, string y)
  {
    return x + ":" + y + " " + Etc;
  }

  public object MissingMethod(MissingMethodCall call)
  {
    if (call.Name == "get_Height") {return 320;}
    if (call.Name == "get_Width") {return 200;}
    return call.Default();
  }
}

Returning a constant value for a fixed number of names isn’t that interesting, but you can imagine how you could use the call name in creative ways to create an illusion of an ad-hoc sub-class of Sample that doesn’t really exist.

Anyway - why do something like this? Because you can is probably the obvious answer. But another example could be something like a POCO viewmodel with virtual properties where the controller is patching in property getter overrides that use closure information to lazy-fetch data back in code that lives in the action. Could help for caching situations where the data may or may not be used during rendering.

[Proof of concept MetaType.zip]