Was at an OpenSpace event today in Stockholm. Was really great. Lots of inspiring discussions. Was in a discussion about Ruby/IronRuby and C# where there was this case where a method call recorder was built with a few lines in Ruby and that it wasn't possible to do it that easy in C#. Well, I kind of disagreed and took up my laptop and put together a few lines (a bit rough) since I just wanted to check if it was doable. The resulting code is below, and yes it is possible.
The case: Create an class that you can invoke methods on dynamically and then replay those calls on another class with the same API.
Note, that the code below isn't optimized but just a proof of concept
You could probably also remove the reflection and use a binder to invoke the method, but I don't know. As I said just a proof of concept.
Calling code
static void Main(string[] args)
{
//Record some calls
dynamic dyn = new Recorder();
dyn.Write("Daniel");
dyn.WriteLine(" Wertheim");
dyn.WriteLine(" building a");
dyn.PlayBackOn(new Writer());
}
The recorder
public class Recorder : DynamicObject
{
private readonly Queue<KeyValuePair<string, object[]>> _calls
= new Queue<KeyValuePair<string, object[]>>();
public override bool TryInvokeMember(
InvokeMemberBinder binder, object[] args, out object result)
{
_calls.Enqueue(new KeyValuePair<string, object[]>(binder.Name, args));
result = null;
return true;
}
public void PlayBackOn<T>(T item)
{
var t = typeof(T);
while(_calls.Count > 0)
{
var kv = _calls.Dequeue();
t.GetMethod(kv.Key).Invoke(item, kv.Value);
}
}
}
The object being played
public class Writer
{
public void Write(string arg)
{
Console.Write(arg);
}
public void WriteLine(string arg)
{
Console.WriteLine(arg);
}
}
As always, have fun.
//Daniel