18

当我想在 C# 中的任何对象上动态调用静态定义的(“在编译时确定”而不是“类级成员”的意义上的“静态”)方法时,我可以使用反射来获取该方法的句柄并调用它:

typeof(Foo).GetMethod("Bar").Invoke(foo, new object[] { /* params */ });

DynamicObject但是,通过从响应(未定义的)实例方法调用继承而使对象动态化TryInvokeMember,并且由于显而易见的原因,类响应的动态方法不会通过反射暴露。这意味着我无法获得应该由 . 响应的方法的方法句柄TryInvokeMember

具有讽刺意味的是,在我看来,您不能dynamic像在非对象上调用已定义方法那样容易地动态调用对象上的动态方法dynamic

我考虑过TryInvokeMember直接调用,但第一个参数必须是InvokeMemberBinder一个抽象类的实例。我觉得如果我必须实现一个类来调用动态对象上的动态方法,我一定是做错了什么。

我如何dynamic通过名称调用对象上的方法,知道目标类没有实现它并且应该使用它来响应它TryInvokeMember

4

2 回答 2

15

我有一个开源(Apache 许可)框架 Dynamitey(在 nuget 中可用),它封装了动态绑定器代码,这包括自动缓存调用站点。它也为每种类型的活页夹(getters、setters、events、indexers、operators、conversions)提供了方便的方法,但特别是你需要InvokeMember

在调用类的静态定义(在编译时)成员时,动态绑定代码实际上比反射(摊销)运行得更快。

Dynamic.InvokeMember(foo,"Bar",arg...);
于 2012-12-10T16:09:06.490 回答
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);

这篇博文和这篇博文有更多关于呼叫站点和活页夹的血腥细节。

于 2012-12-05T02:42:20.210 回答