【问题标题】:Call dynamic methods using reflection in C#在 C# 中使用反射调用动态方法
【发布时间】:2012-10-23 05:08:20
【问题描述】:

我有一个动态实现接口的基于 DynamicObject 的类(通过 TryGet* 和 TryInvoke*)。我想调用它使用反射实现的方法。问题是它抛出了一个 TargetException(对象与目标类型不匹配)。

就像我说的,它是动态的,所以它通过一系列连接将调用作为文本转发到另一个程序,然后该程序使用反射调用目标方法。它基本上是一个代理类。方法名称在编译时是已知的(因为接口),但在外部调用。

typeof(ITelescope).GetMethod(Console.ReadLine()).Invoke(prox,null);

ITelescope 是接口,prox 是动态对象。

【问题讨论】:

  • 你能发布一些代码来演示这个问题吗?

标签: c# dynamic reflection


【解决方案1】:

不幸的是,动态定义的方法不能通过反射获得。部分原因是它们是真正动态的 - 您可以拥有一个动态对象,其中任何方法都有效,因此反射无法在这种情况下正常工作。 (即:GetMethods() 会返回什么?)

如果对象是动态对象,最好的选择通常是将其分配给dynamic,并使用动态绑定来获取您的方法调用:

dynamic yourObj = prox;
yourObj.Unpark();

【讨论】:

  • 您的意思是“动态定义的方法不能通过反射获得”吗?
  • 这不起作用,因为我在编译时不知道方法名称。抱歉,我应该在我的问题中包含这一点,我认为这是不言而喻的。我想我的代码有点误导。我已经对其进行了编辑以反映这一点。
  • 一切都在界面外工作。然后它应该只在 prox 对象中调用它,但它的行为就像它是一个 Typed 对象而不是一个动态对象。调用方法应该经过调用TryInvokeMember的正常流程。
  • @ArlenBeiler 如果对象实际上没有实现接口(仅动态提供接口的成员),那么通过接口调用将不起作用,因为 C# 在其核心是静态类型的,并且不会'不直接支持鸭子类型。在这种情况下,使用提到的 jbtule 之类的库可能是一种更简单的方法(因为您需要获取正确的运行时绑定器来调用成员,这并不简单)
【解决方案2】:

虽然您不能通过反射调用动态方法,但您可以调用 DynamicObject 的 TryGet.../TryInvoke... 方法,这些方法依次执行您的动态方法...

dynamic obj = new MyDyn();
Console.WriteLine(obj.Text);

string methodName = "YourDynamicMethod";                    

var p1 = new ParameterModifier(2);
p1[0] = false; p1[1] = true;

var args = new object[] { new MemberBinder(methodName, true), null };

var res = typeof(DynamicObject).InvokeMember(
    "TryGetMember",
    BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,
    null,
    obj,
    args,
    new ParameterModifier[] { p1 },
    null,
    null);

var result = args[1];

public class MyDyn : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = "#" + binder.Name + "#";
        return true;
    }
}

public class MemberBinder : GetMemberBinder
{
    public MemberBinder(string name, bool ignoreCase) : base(name, ignoreCase)
    {
    }

    public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
    {
        throw new NotImplementedException();
    }
}

【讨论】:

  • 我也不明白这是干什么用的。我觉得很好,我赞成。当您不想或不能添加第三方依赖项(例如 Impromptu)时,这似乎是最佳解决方案。当这样的事情不可行时,还有其他目标客户端,例如 WinRT。
【解决方案3】:

如果您尝试做一些比使用动态关键字更元的事情,您可能会对我编写的 ImpromptuInterface 框架感兴趣(apache 许可,可以在nuget 中找到)。

由于看起来您有一个与动态对象匹配的接口,您可以使用 Impromptu to wrap your dynamic object with an interface impromptu 将动态发出一个静态具有接口的对象,并将调用从该接口转发到动态对象使用dlr。

ITelescope iprox = Impromptu.ActLike(prox);
prox.Unpark();

或者如果你只是想通过字符串名称来调用动态对象的方法,类似于反射,它也有一堆reflection like methods,可以动态调用dlr调用。它比接口方式效率低,但比反射更有效。

Impromptu.InvokeMember(prox,"Unpark");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 2013-07-23
    • 1970-01-01
    相关资源
    最近更新 更多