当我想在C#中的任何对象上动态调用静态定义的(在“编译时确定”意义上的“静态”,而不是“类级别成员”意义上的)方法时,我可以使用反射来获取该方法的句柄并调用它:
typeof(Foo).GetMethod("Bar").Invoke(foo, new object[] { /* params */ });
但是,通过从DynamicObject
继承而变为动态的对象使用TryInvokeMember
响应(未定义的)实例方法调用,并且由于显而易见的原因,类不响应的动态方法不会通过反射公开。这意味着我无法获得应由TryInvokeMember
响应的方法的方法句柄。
具有讽刺意味的是,在我看来,您无法像在dynamic
对象上调用已定义的方法那样轻松地动态调用dynamic
对象上的动态方法。
我考虑直接调用TryInvokeMember
,但第一个参数必须是InvokeMemberBinder
的一个实例,一个抽象类。我觉得如果我必须实现一个类来调用动态对象的动态方法,我一定是做错了。
如何通过名称调用dynamic
对象上的方法,知道目标类不实现它,并且应该使用TryInvokeMember
来响应它?
答案 0 :(得分:14)
我有一个开源(Apache许可证)框架Dynamitey(在nuget中可用),它封装了动态绑定器代码,这包括自动缓存调用站点。它也为每种类型的活页夹提供了方便的方法(getter,setter,事件,索引器,操作符,转换),但具体你想要InvokeMember。
当调用静态定义(在编译时)类的成员时,动态绑定器代码实际上比反射(摊销)运行得更快。
Dynamic.InvokeMember(foo,"Bar",arg...);
答案 1 :(得分:9)
实现它的一种方法是模仿C#编译器为动态对象上的方法调用输出的内容。这需要在[EditorBrowsable(EditorBrowsableState.Never)]
命名空间中使用标记为Microsoft.CSharp.RuntimeBinder
的一堆类型,因此它们在Intellisense中不可见。毋庸置疑,这似乎不是支持的方案,因此使用它需要您自担风险!
此代码调用动态Bar
方法,而不对源自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);