动态构建函数与动态主体使用表达式

本文关键字:动态 主体 表达式 构建 函数 Tn | 更新日期: 2023-09-27 18:08:26

注意:Func<Tn,T> =可以是任意类型

我最近捡起了一个我已经做了一段时间的项目,正在审核代码。在我休息之前,我被一个方法的执行激怒了,所以我花了大约2天的时间来改进它。我试图动态地创建一个Func<>与泛型类型参数计数,类型和返回类型在运行时已知。

我现在使用的当前代码块是这个switch语句:(抱歉格式)

foreach (var member in LinkedDocument.GetType()
                           .GetMethods()
                           .Where(
                               method =>
                                   method.GetCustomAttributes(
                                       typeof(ScriptingMethodAttribute), true)
                                         .Length != 0))
{
Delegate method;
switch (member.GetParameters()
           .Count())
{
    case 0:
        method = new Func<dynamic>(() => member.Invoke(LinkedDocument, null));
        break;
    case 1:
        method = new Func<object, dynamic>(
            param => member.Invoke(
                LinkedDocument, new[]
                {
                    param
                }));
        break;
    case 2:
        method =
            new Func<object, object, dynamic>(
                (param1, param2) => member.Invoke(
                    LinkedDocument, new[]
                    {
                        param1,
                        param2
                    }));
        break;
    case 3:
        method =
            new Func<object, object, object, dynamic>(
                (param1, param2, param3) => member.Invoke(
                    LinkedDocument, new[]
                    {
                        param1,
                        param2,
                        param3
                    }));
        break;
    case 4:
        method =
            new Func<object, object, object, object, dynamic>(
                (param1, param2, param3, param4) => member.Invoke(
                    LinkedDocument, new[]
                    {
                        param1,
                        param2,
                        param3,
                        param4
                    }));
        break;
    default:
        throw new NotImplementedException();
}
initalScope.Add(member.Name.ToLower(), method);

}我试图使用表达式树的动态构建它,我正在阅读教程,但我只是没有得到它。我看到的所有例子都使用静态类型exp: Func<object, object, dynamic>

我不想做这个。我想根据方法参数计数动态地构建它。这是我到目前为止得到的……

var assem = System.Reflection.Assembly.GetAssembly(typeof(Func<object>));
var type = assem.GetType(string.Format("Func`{0}", obj.GetParameters().Count()));
var typeArr = obj.GetParameters().Select(param => param.ParameterType).ToList();
typeArr.Add(obj.ReturnType);
var ctrInfo = type.GetConstructor(typeArr.ToArray());
var expType = Expression.New(type);

,我认为这是Expression发挥作用的地方。但是我真的很难理解教程以及如何将解决方案集成到我的问题中。

注意:我不想解决我的具体问题,只是一些指导会很好。

谢谢你的帮助。

:


在重新考虑我的实现时,我记得为什么我不想使用object[]

我仍然需要这样写:

switch (member.GetParameters().Count())
{
    case 0:
        method = new Func<dynamic>(() => member.Invoke(LinkedDocument, null));
        break;
    case 1:
        method = new Func<object, dynamic>(param => member.Invoke(LinkedDocument, new[] { param }));
        break;
    default:
        method = new Func<object[], dynamic>(
            param => member.Invoke(
                LinkedDocument, param));
        break;
}

或:

var paramCount = member.GetParameters().Count();
if(paramCount == 0)
    method = new Func<dynamic>(() => member.Invoke(LinkedDocument, null));
else if(paramCount == 1)
    method = new Func<object, dynamic>(param => member.Invoke(LinkedDocument, new[] { param }));
else
    method = new Func<object[], dynamic>(
           param => member.Invoke(
               LinkedDocument, param));

工作……但是…我只是觉得可以更动态地包含所有的方法

动态构建函数<Tn,T>与动态主体使用表达式

  1. 获取ParameterExpressions的列表。我通过调用GetParameters,然后使用Select和ToList从ParameterInfo转换为ParameterExpression
  2. 创建一个表达式,用参数调用你的方法
  3. 确定委托类型。它看起来像你有一个工作方法,但我也包括我的代码下面。
  4. 创建一个lambda表达式,传递你的委托类型、调用方法的表达式(这是lambda表达式的主体)和你的参数。
  5. 设置"method"等于lambda表达式的编译版本。
  6. 对委托做任何你想做的事。
代码:

foreach (var member in LinkedDocument.GetType()
                       .GetMethods()
                       .Where(
                           method =>
                               method.GetCustomAttributes(
                                   typeof(ScriptingMethodAttribute), true)
                                     .Length != 0))
{
    var parameters = member.GetParameters().Select(v => Expression.Parameter(v.ParameterType, v.Name)).ToList();
    var caller = Expression.Call(member, parameters);
    var delegateType = GetFuncType(member.GetParameters().Select(v => v.ParameterType).ToArray(), member.ReturnType);
    var methodLambda = Expression.Lambda(delegateType, caller, parameters);
    Delegate method = methodLambda.Compile();
    initalScope.Add(member.Name.ToLower(), method);
}
下面是我用来获取委托/函数类型 的代码
public static Type[] _baseFuncTypes = new Type[] { typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>), typeof(Func<,,,,>), typeof(Func<,,,,,>), typeof(Func<,,,,,,>), typeof(Func<,,,,,,,>), typeof(Func<,,,,,,,,>) };
private static Type GetFuncType(Type[] parameterTypes, Type returnType)
{
    Array.Resize(ref parameterTypes, parameterTypes.Length + 1);
    parameterTypes[parameterTypes.Length - 1] = returnType;
    return _baseFuncTypes[parameterTypes.Length - 1].MakeGenericType(parameterTypes);
}