Monday, June 6, 2011

More on DynamicObject: TryInvokeMember

I just came along another old example of DynamicObject, I would like to share with the world.

What I didn't mention in my last post is that DynamicObject has more methods you can override besides TryGetMember and TrySetMember. These two are very useful when working with properties you want to add on the fly. For methods the TryInvokeMember is a better choice to override. This method will get called on your DynamicObject when it can't resolve a method call.

Let's for instance write a very simple dynamic tracer class. First of all I will inherit again from DynamicObject. This time the class I am creating, DynamicTracer, will not hold an XML tree, but it will wrap another object.

Every time a method is called on this object we will print out (hence the name DynamicTracer) the operation that is being called.

 class DynamicTracer : DynamicObject 
 { 
   object theObject; 
   public DynamicTracer(object theObject) 
   { 
     this.theObject = theObject; 
   } 
   public override bool TryInvokeMember(InvokeMemberBinder binder, 
      object[] args, out object result) 
   { 
     try 
     { 
       Console.WriteLine("Invoking {0} on {1}", binder.Name, 
            theObject.ToString()); 
       Type objectType = theObject.GetType(); 
       result = objectType.InvokeMember(binder.Name, 
            System.Reflection.BindingFlags.InvokeMethod, null, 
            theObject, args); 
       return true; 
     } 
     catch 
     { 
       Console.WriteLine("Oops, cannot resolve {0} to {1}", 
            binder.Name, theObject.ToString()); 
       result = null; 
       return false; 
     } 
     return true;
   } 
 }  

The usage is quite similar to using TryGetMember and TrySetMember, only now are we getting a InvokeMemberBinder as parameter, together with the argument list that is being used and an out parameter for returning the result. I use reflection to invoke the method on the actual object.

To use this tracer, the only thing you need to do is wrap an object with it:

 FileInfo fi = new FileInfo("c:\\temp\\test.txt"); 
 dynamic tracedFI = new DynamicTracer(fi); 
 tracedFI.Create();  

When Create is called, there will be no matching method found in the DynamicTracer class, which will instead trigger the TryInvokeMember method. Although this seems pretty cool and useful, beware you loose all auto completion on any object you wrap this way, which is, for all things dynamic, a downside.

No comments:

Post a Comment