Using C# dynamic to call static members


By now, you’ve probably heard that C# 4.0 is adding support for the dynamic keyword, which introduces some aspects of dynamic languages to C#.  I had not had a chance to really try it, but recently I was reading Bertrand Le Roy’s post on the topic, and was sort of looking for a good opportunity to use it.

Today, I found a scenario which I thought it would work great for, but it turned out not to be supported out of the box!

The scenario is to call static class members using dynamic.  That probably sounds crazy, so let’s look at an example.  Say you have these two classes:

public class Foo1 {
    public static string TransformString(string s) { return s.ToLower(); }
    public static string MyConstant { get { return "Constant from Foo1"; } }
}

public class Foo2 {
    public static string TransformString(string s) { return s.ToUpper(); }
    public static string MyConstant { get { return "Constant from Foo2"; } }
}

Note that they are unrelated classes, but share some members with the same signature.  In a sense, you could say that they two classes share a duck type signature.

Now here is the problem we’re trying to solve: given a System.Type object of either class (or any other random class that shares those members), how can you call those members?  Concretely, we’re trying to implement this method:

static void MakeTestCalls(Type type) {
    // Call TransformString("Hello World") on this type

    // Get the MyConstant property on this type
}

How can we implement this method? Ok, we can do it the old fashion way using reflection, e.g.

static void MakeTestCalls(Type type) {
    Console.WriteLine(type.GetMethod("TransformString").Invoke(null, new object[] { "Hello World" }));
    Console.WriteLine(type.GetProperty("MyConstant").GetValue(null, null));
}

That works, but it’s ugly.  These are the very type of things that dynamic is supposed to improve.  So my first naive attempt was to do this:

static void MakeTestCalls(Type type) {
    dynamic fooTypeDynamic = type;

    Console.WriteLine(fooTypeDynamic.TransformString("Hello World"));
    Console.WriteLine(fooTypeDynamic.MyConstant);
}

Basically, the theory was that when assigning a System.Type to a dynamic variable, it would let you call static members from it.  I didn’t really expect it to work, but I at least had to try! 🙂  And sure enough, it didn’t work, blowing up with: “Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ‘System.RuntimeType’ does not contain a definition for ‘TransformString’”.

So I then posted the question on our internal C# list, and got a reply from C# guru Eric Lippert, basically saying that it was a potentially interesting idea but was just not supported in C# 4.0.  Fair enough, this is only the beginning of C# dynamic, and it doesn’t do everything.

But I then went back to Bertrand’s post where he gives a great sample of how you can teach dymamic new tricks by implementing a custom DynamicObject.  And it turned out to be relative simple.  Here is the class I ended up with:

public class StaticMembersDynamicWrapper : DynamicObject {
    private Type _type;
    public StaticMembersDynamicWrapper(Type type) { _type = type; }

    // Handle static properties
    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        PropertyInfo prop = _type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
        if (prop == null) {
            result = null;
            return false;
        }

        result = prop.GetValue(null, null);
        return true;
    }

    // Handle static methods
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
        MethodInfo method = _type.GetMethod(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
        if (method == null) {
            result = null;
            return false;
        }

        result = method.Invoke(null, args);
        return true;
    }
}

The idea is pretty simple: when the runtime needs to call something, it basically asks you to do it.  It passes you the method (or property) name and the parameters, and you take it from there. And in this case, of course, we’re using reflection.

Once we have that, the real fun starts as we’re now able to call our static members using dynamic!

static void MakeTestCalls(Type type) {
    dynamic typeDynamic = new StaticMembersDynamicWrapper(type);

    // Call TransformString("Hello World") on this type
    Console.WriteLine(typeDynamic.TransformString("Hello World"));

    // Get the MyConstant property on this type
    Console.WriteLine(typeDynamic.MyConstant);
}

Note how we wrap the type into our custom DynamicObject is order to have the dynamic invocations go through us.

Now you might say that the scenario above where you have two classes with identical static members doesn’t seem like something that would actually occur commonly in real apps.  But once you start bringing in generics, it can actually be more common.  e.g. suppose you have something like:

public class Table<T> {
    public static IEnumerable<T> Records { get { [return records from database table T] } }
}

The idea is that the class is an abstraction for a database table.  So Table<Product>.Records returns an IEnumerable<Products>, and Table<Category>.Records returns an IEnumerable<Category>.  Now suppose you’re writing some table agnostic code that can work with the data from any table.  You have a System.Type for some Table<T>, and you need to get its Records property.  Even though it seems like it’s the same Records property coming for a base class, the reality is that it’s a completely different property for each T, and C# provides no simple way of making the call.  But with the technique above, you get to access the property with a much simpler syntax than with reflection.

The zipped sample is attached to this post.

DynamicCallsToStaticMembers.zip

Comments (17)

  1. YT says:

    it  seems like a ordinary case to me…

  2. Andre says:

    Nice idea – thank you for the sample.

    But can’t the same be accomplished with delegates / interfaces ?

    Besides that the dynamic binding seems to have a high runtime overhead, compared to delegates.

    Andre

  3. Andre says:

    O.k. tried it.

    No (simple) way to bind a delegate dynamically to an unknown types function without using reflections invoke – I’m still too much influenced by C++ template binding possibilites 😉

    So your sample is the only way to accomplish that in C# for generic types (easily).

    A cool method for generic static calls, where the overhead is negligible. Although I still would prefer static bindings over dynamic ones, to catch most of the bugs at compilation time.

    Andre

  4. davidebb says:

    @Andre: I’m with you on favoring static bindings whenever possible. But for cases where they’re not easily possible, ‘dynamic’ offers a cleaner syntax than its alternatives.

  5. Jayson says:

    I can see this being useful when you’re "duct-taping" classes in 3rd party libraries… however, if you own the classes, I would prefer the use of interfaces (as both you and Andre already mentioned).

    Interesting read, nonetheless 🙂 Thanks

  6. Hy

    Thanks for this insight. Although I’m a bit skeptic about the over usage of dynamic keyword. I also prefer the usage of a strict and strongly typed domain over the dynamic approach. In my point of view the dynamic approach should only be used in rare cases because actually during design time you have no guarantee that what your are coding is semantically correct and you get the surprises when you are executing your program.

    Daniel

  7. Jack says:

    dynamic call, quite cool feature!

  8. Coincidence, three days ago I posted a ‘proposal’ (nothing official here…) for static interface to resolve this kind of thing in C#.

    You can read it here : http://thinkbeforecoding.com/post/2009/10/21/CSharp-Static-interfaces

    and here

    http://thinkbeforecoding.com/post/2009/10/22/CSharp-Static-interfaces-Take-2

  9. WebGrid says:

    Hi,

    It’s like Jayson says it’s nice for "duct-taping" 3rd party libraries.

    It saved my day! 🙂

  10. davidebb says:

    @Jérémie: the idea of static interfaces is potentially interesting.  One different is that in your case, you have T has a generic type param (as in IsInstanciated<T>() where T: ICountable). But how would you ‘cast’ to this interface if all you had was a System.Type, in a really late bound scenario?

  11. David Kujawski says:

    Nice work, this is useful, however there are two problems with your approach:

      1) no handling of overloaded methods

      2) incorrect handling of optional/named parameters

    I can’t post the code here (in the comments since it would look terrible), but I was able modify the code to check the Binder and get the Parameters for the methods of the type to correctly handle the two issues above.

    Thanks for the headstart!

  12. davidebb says:

    @David Kujawski: indeed, my code above is just a proof of concept and doesn’t deal with cases like method overloading.  Thanks for pointing this out!

  13. Paul Batum says:

    This is a nice in that it is an easy to follow example of using the DynamicObject class, but…

    Even in the case where you are forced to rely on 3rd party libraries that are exposing the functionality you need as static methods, you should be able to wrap that functionality inside your own classes and then have them implement a common interface. Therefore I am skeptical about whether the above approach is actually something you would ever want to do.

  14. Thanks for this.  You can take it a step further with extension methods:

    <code>

           static readonly Dictionary<Type, StaticMembersDynamicWrapper> _typeLookup = new Dictionary<Type, StaticMembersDynamicWrapper>();

           public static dynamic StaticMembersProxy(this Type type)

           {

               StaticMembersDynamicWrapper smdw;

               if (!_typeLookup.TryGetValue(type, out smdw))

                   _typeLookup[type] = smdw = new StaticMembersDynamicWrapper(type);

               return smdw;

           }

    </code>

  15. davidebb says:

    @Stephen: agreed, that’s a nice little addition.

  16. Omer Raviv says:

    This could've been great for the various .Parse method overloads that the primitive BCL types provide (The Convert class doesn't solve everything.)

  17. Gregory Chernis says:

    With some help, worked out a way to access the constant fields too:

    stackoverflow.com/…/accessing-constants-with-a-dynamic-keyword