使用C#中的反射调用动态方法

时间:2012-10-22 17:05:04

标签: c# dynamic reflection

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

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

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

ITelescope是界面,prox是动态对象。

3 个答案:

答案 0 :(得分:4)

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

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

dynamic yourObj = prox;
yourObj.Unpark();

答案 1 :(得分:3)

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

由于看起来你有一个与你的动态对象匹配的接口,你可以使用Impromptu来wrap your dynamic object with an interface即兴将动态发出一个静态有接口的对象,并将来自该接口的调用转发给动态使用dlr的对象。

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

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

Impromptu.InvokeMember(prox,"Unpark");

答案 2 :(得分:3)

虽然您无法使用反射调用动态方法,但您可以调用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();
    }
}