【问题标题】:Link general method to delegate将通用方法链接到委托
【发布时间】:2017-07-19 09:02:38
【问题描述】:

我希望能够将方法链接到所有类型的委托。我正在尝试使用refelection.emit 执行此操作,并将动态方法与委托的足迹链接,将其添加到委托并让此动态方法调用具有所有参数的通用函数。但我希望有更简单的方法来做到这一点。

(我没有包含 reflection.emit 代码,因为这不是我想要的帮助,这仍然是一个原始尝试)

这是我想要得到的结果示例:

public class FooClass
    {
        public delegate string MyFirstDelegate(string input1, string input2);
        public delegate int MySecondDelegate(int input1, string input2, short input3);

        public static MyFirstDelegate firstDelegate = null;
        public static MySecondDelegate SecondDelegate = null;

        private static string FirstMethod(string input1, string input2)
        {
            return input1 + input2;
        }

        private static int SecondMethod(int input1, string input2, short input3)
        {
            return input1 + Convert.ToInt32(input2) + input3;
        }

        private static object ThirdMethod(params object[] inputs)
        {
            //do some magic and return result
        }

        public static void Main()
        {
            firstDelegate = FirstMethod;
            SecondDelegate = SecondMethod;

            string result = firstDelegate("1", "2");
            int result2 = SecondDelegate(1, "3", 3);

            //obviously this does not work, but is there a way to link this method to the delegate?
            firstDelegate = ThirdMethod;    
            SecondDelegate = ThirdMethod;

            string result3 = firstDelegate("1", "2");
            int result4 = SecondDelegate(1, "3", 3);
        }
    }

【问题讨论】:

    标签: c# delegates reflection.emit


    【解决方案1】:

    要将方法链接到所有类型的委托,您可以使用 Expression 像这样创建辅助方法:

    private static TTarget ConvertDelegate<TTarget>(MethodInfo source)
    {
        var targetMethod = typeof(TTarget).GetMethod("Invoke");
        var parameters = targetMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
        var methodCall = Expression.Call(source, Expression.NewArrayInit(typeof(object), parameters));
        var delegateExpression = Expression.Lambda<TTarget>(Expression.TypeAs(methodCall, targetMethod.ReturnType), parameters);
        return delegateExpression.Compile();
    }
    

    那么你可以这样使用它:

    var methodInfo= typeof(FooClass).GetMethod(nameof(ThirdMethod), BindingFlags.NonPublic | BindingFlags.Static);
    firstDelegate = ConvertDelegate<MyFirstDelegate>(methodInfo);
    

    我还创建了辅助方法来从方法名称中获取MethodInfo

    private static MethodInfo GetMethodInfo<T>(string methodName)
    {
        return typeof(T).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static);
    }
    
    private static TTarget ConvertDelegate<TTarget, TSource>(string sourceMethodName)
    {
        return ConvertDelegate<TTarget>(GetMethodInfo<TSource>(sourceMethodName));
    } 
    

    那么你可以这样使用它:

    firstDelegate = ConvertDelegate<MyFirstDelegate, FooClass>(nameof(ThirdMethod));
    

    不要忘记ConvertDelegate 只会包装带有签名object Name(object[] inputs) 的方法,如果您只需要包装一种方法,您可以将MethodInfo 保存在某个本地值中,并且不要每次都作为参数传递。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-20
      • 2016-05-22
      • 1970-01-01
      • 1970-01-01
      • 2015-09-01
      • 1970-01-01
      相关资源
      最近更新 更多