当a的方法有参数时,如何创建Func <a,b>的委托

时间:2015-08-27 00:22:18

标签: c# function reflection delegates

我试图调用一个接受函数的方法,但是使用relection。当方法是无参数的时候我已经让它工作了但是当有参数时我无法弄清楚如何调用它。这是一个人为的简化示例,但这可以归结为问题。我不会知道在运行时添加的参数。

任何指针?我必须使用表达式树吗?有更简单的方法吗?

public void Main()
{
    //works
    CallFunction(typeof (Processor), "Count");
    //I don't understand what I need to modify to make add work
    CallFunction(typeof (Processor), "Add");
}

public void CallFunction(Type type, string methodToCall)
{
    var targetMethod = type.GetMethod(methodToCall);
    var constructedType = typeof (MethodCaller<>).MakeGenericType(type);
    dynamic target = Activator.CreateInstance(constructedType);
    var method = constructedType.GetMethod("Do").MakeGenericMethod(targetMethod.ReturnType);
    var func =  typeof (Func<,>).MakeGenericType(type, targetMethod.ReturnType);
    var toCall = Delegate.CreateDelegate(func, targetMethod);
    method.Invoke(target, new object[] { toCall });
}

public class Processor
{
    public int Count()
    {
        return 1;
    }
    public int Add(int toAdd)
    {
        return 1 + toAdd;
    }
}

public class MethodCaller<TParm> where TParm : new()
{
    public TResult Do<TResult>(Func<TParm, TResult> func)
    {
        return func(new TParm());
    }
}

2 个答案:

答案 0 :(得分:2)

type.InvokeMember(method_name, System.Reflection.BindingFlags.InvokeMethod, null, type_instance, new object[] { param1, param2, param3 });

https://msdn.microsoft.com/en-us/library/66btctbe(v=vs.110).aspx

实际上整个CallFunction方法可以简化为:

public void CallFunction(Type type, string methodToCall, params object[] args)
{
    // Why this part is so complex? Do I miss something?
    //var constructedType = typeof (MethodCaller<>).MakeGenericType(type);
    //dynamic target = Activator.CreateInstance(constructedType);

    var target = Activator.CreateInstance(type);
    var result = type.InvokeMember(method_name, System.Reflection.BindingFlags.InvokeMethod, null, target, args);
    // ... do something with result if you need ...
}

如果您需要MethodCaller.Do,但可以牺牲签名上的类型(或DoTyped装箱/拆箱时的某些表现

public void CallFunction(Type type, string methodToCall, params object[] args)
{
    var delegate_wrapper = new Func<object, object>(
        instance => type.InvokeMember(methodToCall, BindingFlags.InvokeMethod, null, instance, args)
        );
    var target_method = type.GetMethod(methodToCall);

    var mc_custom_type = typeof (MethodCaller<>).MakeGenericType(type);
    var mc_instance = Activator.CreateInstance(mc_custom_type);
    var mc_custom_method = mc_custom_type.GetMethod("Do").MakeGenericMethod(target_method.ReturnType);

    mc_custom_method.Invoke(mc_instance, new object[] { delegate_wrapper });
}

public class MethodCaller<TParm> where TParm : new()
{
    public TResult DoTyped<TResult>(Func<TParm, TResult> func)
    {
        return Do<TResult>(oinstance=>func((TParm)oinstance));
    }

    public TResult Do<TResult>(Func<object, object> func)
    {
        Console.WriteLine("I AM DO");
        return (TResult)func(new TParm());
    }
}

答案 1 :(得分:0)

您是否尝试过使用Impromptu框架?它主要用于鸭子打字,但是库提供了相当灵活的API来访问方法和传递参数。

https://github.com/ekonbenefits/impromptu-interface/wiki/UsageReallyLateBinding