Saturday, March 19, 2011

Fun with DynamicObject and making .NET reflection less painful

If you're a Microsoft techie, you probably noticed that RC1 of Entity Framework 4.1 was released this week.  One of the things I've been waiting for with EF is the ability to run cross database queries on the same server - for example, being able to join MyDB.dbo.MyTable to YourDB.dbo.YourTable when MyDB and YourDB are SQL Server databases on the same server.  It's crazy that MS hasn't added this feature yet, since they seem to want to speed up EF adoption and since Linq-to-SQL does this perfectly.  But, I don't want to actually talk about this... this isn't what this post is about.  This issue is what started me on a different track.

You see, I wondered if there was a way to hack this functionality in by examining the EF code using Red Gate's Reflector tool.  As I examined the guts of EF, the parts that mattered were buried deep in the code - internal objects and private properties and methods.  Figuring out the code seemed like it would be way easier if I could examine the guts and change parts at run-time (I haven't figured this out by the way, so if you're here hoping I cracked this nut, you need to go back to Microsoft and the EF team and complain to them).  In order to really examine the code though, I'd need to use reflection and call methods and properties of private areas of the code, which is always a painful experience.  And that's when I turned to the new dynamic features of C#, and is the topic of this post.

If you don't know about the dynamic keyword in C#, it's purpose is to remove the compile time type safety on a variable.  If a variable is declared dynamic, you can call properties and methods on the variable and those calls aren't handled until run-time.  Those properties and methods may not exist, but you can intercept those calls and do some magic with them, like dynamically adding those properties or methods to the object.  See this stackoverflow question here and my answer to get some idea of how this works.  This sort of thing is nothing new for users of dynamic languages like Ruby, but for compile time checked languages, this is a really nice advancement.

So, all that to say, I decided to experiment with the dynamic features to provide a much simpler way of accessing private and protected aspects of a class at run-time.  I've code named this project "LookingGlass" as a play on reflection.  Here's a sample:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.Reflection;

public class LookingGlass : DynamicObject {
 public dynamic TheObject { get; private set; }
 public Type TheObjectType;

 public LookingGlass(dynamic theObject) {
  this.TheObject = theObject;
  this.TheObjectType = this.TheObject.GetType();
 }

 public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
  result = null;
  int index = (int)indexes[0];
  var value = this.TheObject[index];
  result = new LookingGlass(value);
  return true;
 }

 public override bool TryGetMember(GetMemberBinder binder, out object result) {
  result = null;

  var field = GetField(binder.Name);
  if (field != null) {
   var value = field.GetValue(this.TheObject);
   result = new LookingGlass(value);
   return true;
  }

  var prop = GetProperty(binder.Name);
  if (prop != null) {
   var value = prop.GetValue(this.TheObject, null);
   result = new LookingGlass(value);
   return true;
  }
   
  return false;
 }

 public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
  result = null;
  var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod;
  var value = this.TheObjectType.InvokeMember(binder.Name, flags, Type.DefaultBinder, this.TheObject, args);
  if (value != null) {
   result = new LookingGlass(value);
  }
  return true;
 }

 private FieldInfo GetField(string fieldName) {
  var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
  var field = this.TheObjectType.GetField(fieldName, flags);
  return field;
 }

 private PropertyInfo GetProperty(string propertyName) {
  var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
  var prop = this.TheObjectType.GetProperty(propertyName, flags);
  return prop;
 }

 public override string ToString() {
  return this.TheObject.ToString();
 }
}

Obviously, this is quite a lot to take in, but the gist of this is that this lets you open up any object as if it's private fields, methods, and properties were all public.  It's not exactly fast, nor was it designed to be robust if the thing you're calling isn't part of that object, but this solved my immediate need of inspecting some of the Entity Framework guts at run time.  To use this, make yourself a class called Test() and put some private fields, methods, or properties on it and then call it like this:

var tst = new Test();
dynamic totallyOpenObj = new LookingGlass(tst);
Console.WriteLine(totallyOpenObj._privateField);
Console.WriteLine(totallyOpenObj.InternalMethod("asdf"));
Console.WriteLine(totallyOpenObj.PrivateProp.PrvProp2[10]);

You can also chain calls as each object returned is a new dynamic LookingGlass object that lets you explore it as well.  It handles overloaded methods and indexers too.  If you'd like to change the objects you're interrogating, DynamicObject lets you override TrySetMember and TrySetIndex and their ilk.  Hope this gives you some ideas on where you can go with the new dynamic features in C#.  This opens up a whole new world of possibilities for C# devs.  Happy coding!