tags:

views:

410

answers:

1

Given the new dynamic support in C# 4, is it possible to write a class in such a way that if a method is invoked on an instance and that method is not present, dispatch is passed to another method? This might look something like:

public class Apple : ... {
  // ...

  private ... MethodMissing(string name, ...) {
    if (name == "TurnIntoOrange") {
      // do something
    }
  }
}

dynamic d = new Apple();
d.TurnIntoOrange();       // Not actually defined on Apple; will pass to MethodMissing.

Other languages would call this "method_missing support", under the more general heading of metaprogramming. I'm not sure what C# calls this specifically. But is it possible?

+11  A: 

Absolutely. Either implement IDynamicMetaObjectProvider or derive from DynamicObject for a much simpler route. See the DLR documentation for some good examples.

Here's a quick example of DynamicObject:

using System;
using System.Dynamic;

public class MyDynamic : DynamicObject
{
    public override bool TryInvokeMember
        (InvokeMemberBinder binder,
         object[] args,
         out object result)
    {
        Console.WriteLine("I would have invoked: {0}",
                          binder.Name);
        result = "dummy";
        return true;
    }

    public string NormalMethod()
    {
        Console.WriteLine("In NormalMethod");
        return "normal";
    }
}

class Test
{
    static void Main()
    {
        dynamic d = new MyDynamic();
        Console.WriteLine(d.HelloWorld());
        Console.WriteLine(d.NormalMethod());
    }
}

<plug>

I have a bigger example of DynamicObject in the 2nd edition of C# in Depth but I haven't yet implemented IDyamicMetaObjectProvider. I'll do so before the book's release, but the early access edition only has the DynamicObject example at the moment. Btw, if you buy it today it's half price - use the code twtr0711. I'll edit this answer later on to remove that bit :)

</plug>

Jon Skeet
Wow, thanks Jon!
Kyle Kaitan
I alluded to this in my title but didn't directly ask it in the body: Is there a similar override I'd use to mimic a "responds_to" method.? I see that I can check the result of TryInvokeMember, but that might result in undesirable side effects.
Kyle Kaitan
No, I don't believe there's any way of asking a dynamic method whether it will handle anything - although you could call GetDynamicMemberNames as a starting point.
Jon Skeet
Jon, how to call your dynamic object from VB.NET code?
Prankster
GetDynamicMemberNames() is an optional thing, i.e. a class inheriting from DynamicObject can override it if it wants, but if it doesn't the function in the base class gets called which returns an empty list.
Matt Warren