扩展Func以接受C#中的数组参数

时间:2017-12-03 01:38:52

标签: c# linq delegates

我一直在使用Func来创建

Expression.Lambda<Func<object, object>>(block, paramValues).Compile();

其中block是Expression.Block,用于创建所需的执行计划。 paramValues是Expression.Parameter值的数组:

 var paramValues = epDef.Value.Parameters.Select(p => Expression.Parameter(typeof(object), p.Name))
            .ToArray();

我试图修改它以接受一个数组,这样当我有超过16个输入参数时我可以使用Func:

Expression.Lambda<Func<object[], object>>(block, paramValues).Compile();

然而,这给了我以下错误:

Incorrect number of parameters supplied for lambda declaration

在这种情况下,有人可以帮助我使用Func接受16个以上的参数吗?使用数组作为输入或创建自定义委托

@MethodMan:

我试图在那个问题中实现解决方案,但我得到了同样的错误。根据我的理解,将Expression.Parameter从typeof(object)更改为typeof(object[])应该适用于我的情况,但我得到了相同的错误

编辑:

这是我从链接版本中尝试的修改版本:

class Program
    {
        static void Main(string[] argas)
        {
            Type[] types = new Type[] { typeof(object[]) };

            var constructorInfo = typeof(Program).GetConstructor(types);
            var parameters = types.Select((t, i) => Expression.Parameter(t, "p" + i)).ToArray();
            var someType1Exp = Expression.New(constructorInfo, parameters);
            var inner = Expression.Lambda(someType1Exp, parameters);

            var args = Expression.Parameter(typeof(object[]), "args");
            var body = Expression.Invoke(inner,
                parameters.Select((p, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), p.Type)).ToArray());
            var outer = Expression.Lambda<Func<object[], object>>(body, args);
            var func = outer.Compile();

            object[] values = { 1, 123.45F, "abc" };
            object obj = func(values);
            Console.WriteLine(obj);
            Console.WriteLine("test");
            Console.ReadLine();
        }
        //public Program() { }
        public Program(object[] values) { Console.WriteLine(values.ToString()); }

    }

我收到以下错误:

System.InvalidCastException: 'Unable to cast object of type 'System.Int32' to type 'System.Object[]'.'

1 个答案:

答案 0 :(得分:0)

你有问题是你改变你的lambda采用单个数组参数object[]但是你仍然传递多个参数(paramValues)。您需要传入一个值Array。您还需要修改表达式主体以期望数组。

在你有相同的

之前考虑一下
(a,b,c,d) => new Program(a, b, c, d)

现在你想要

(object[] a) => new Program((type0)a[0], (type1)a[1], (type2)a[2], (type3)a[3])

因此,您需要修改代码以直接引用参数数组的元素而不是参数:

class Program
    {
        static void Main(string[] argas)
        {
            var constructorInfo = typeof(Program).GetConstructors()[0];
            var types = constructorInfo.GetParameters().Select(p => p.ParameterType);
            var parm = Expression.Parameter(typeof(object[]), "args");
            var parameters = types.Select((t, i) => Expression.Convert(Expression.ArrayIndex(parm, Expression.Constant(i)), t)).ToArray();
            var someType1Exp = Expression.New(constructorInfo, parameters);
            var outer = Expression.Lambda<Func<object[], object>>(someType1Exp, parm);
            var func = outer.Compile();

            object[] values = { 1, 123.45F, "abc" };
            object obj = func(values);
            Console.WriteLine(obj);
            Console.WriteLine("test");
            Console.ReadLine();
        }

        //public Program() { }
        public Program(int val1, float val2, string val3) { 
            Console.WriteLine(val1);
            Console.WriteLine(val2);
            Console.WriteLine(val3);
        }
    }

如果要将object[]传递给构造函数,如

(object[] args) => new Program(args)

你可以直接这样做(抱歉格式化,从我的LINQPad复制):

public class Program  {
void Main() {
    var constructorInfo = typeof(Program).GetConstructors()[0];
    var parm = Expression.Parameter(typeof(object[]), "args");
    var someType1Exp = Expression.New(constructorInfo, parm);
    var outer = Expression.Lambda<Func<object[], object>>(someType1Exp, parm);
    var func = outer.Compile();

    object[] values = { 1, 123.45F, "abc" };
    object obj = func(values);
    Console.WriteLine(obj);
    Console.WriteLine("test");
}

// Define other methods and classes here
    public Program(object[] parms) {
        Console.WriteLine(parms.ToString());
    }
}