使用Expression </tn,t>使用动态主体动态构建Func <tn,t>

时间:2014-06-12 16:42:44

标签: c# dynamic delegates expression func

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

我最近选择了一个我已经工作了一段时间的项目并且正在审核代码。在我休息之前,我因为一种方法的实施而变得更加糟糕,所以我花了大约2天的时间来努力使它变得更好。我正在尝试动态创建Func<>,其中包含在运行时已知的泛型类型参数count,type和return类型。

我现在使用的当前代码块是这个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));

哪个有效......但是......我认为可以更加动态地完成它以包含所有方法。

1 个答案:

答案 0 :(得分:0)

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

    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);
    }
    

    以下是我用来获取委托/ func类型的代码

    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);
    }