When I want to dynamically call a statically-defined ("statically" in the sense of "determined at compile-time", not in the sense of "class-level member") method on any object in C#, I can use reflection to get a handle to that method and invoke it:
typeof(Foo).GetMethod("Bar").Invoke(foo, new object[] { /* params */ });
However, objects made dynamic by inheriting from DynamicObject
respond to (undefined) instance method calls using TryInvokeMember
, and the dynamic methods the class responds to are not exposed through reflection, for obvious reasons. This means that I can't get a method handle for a method that should be responded to by TryInvokeMember
.
So ironically, it seems to me that you can't dynamically call a dynamic method on a dynamic
object as easily as you can call a defined method on a non-dynamic
object.
I've considered calling TryInvokeMember
directly, but the first argument must be an instance of an InvokeMemberBinder
, an abstract class. I feel that if I have to implement a class to call a dynamic method on a dynamic object, I must be doing something wrong.
How can I call a method on a dynamic
object by its name, knowing that the target class does not implement it and that it should be responded to using TryInvokeMember
?
One way to go about it is to mimic what the C# compiler outputs for method invocations on dynamic objects. This requires the usage of a bunch of types marked [EditorBrowsable(EditorBrowsableState.Never)]
in the Microsoft.CSharp.RuntimeBinder
namespace, so they will not be visible in Intellisense. Needless to say, this doesn't seem like a supported scenario, so use it at your own risk!
This code calls the dynamic Bar
method without any arguments on an instance of a class derived from DynamicObject
:
dynamic dynamicObject = new DerivedFromDynamicObject();
var callSiteBinder = Binder.InvokeMember(CSharpBinderFlags.None, "Bar", Enumerable.Empty<Type>(), typeof(Program),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var callSite = CallSite<Action<CallSite, object>>.Create(callSiteBinder);
callSite.Target(callSite, dynamicObject);
This blog post and this one have more gory details on call sites and binders.