Пример #1
0
        static LambdaExpression WrapMethodParams(LambdaExpression functionLambda)
        {
            /* We are converting:
             *     [ExcelFunction(...)]
             *     public static string myFunc(string input, int otherInput, params object[] args)
             *     {
             *          ...
             *     }
             *
             * into:
             *     [ExcelFunction(...)]
             *     public static string myFunc(string input, int otherInput, object arg3, object arg4, object arg5, object arg6, {...until...}, object arg125)
             *     {
             *         // First we figure where in the list to stop building the param array
             *         int lastArgToAdd = 0;
             *         if (!(arg3 is ExcelMissing)) lastArgToAdd = 3;
             *         if (!(arg4 is ExcelMissing)) lastArgToAdd = 4;
             *         ...
             *         if (!(arg125 is ExcelMissing)) lastArgToAdd = 125;
             *
             *         // Then add until we get there
             *         List<object> args = new List<object>();
             *         if (lastArgToAdd >= 3) args.Add(arg3);
             *         if (lastArgToAdd >= 4) args.Add(arg4);
             *         ...
             *         if (lastArgToAdd >= 125) args.Add(arg125);
             *
             *         Array<object> argsArray = args.ToArray();
             *         return myFunc(input, otherInput, argsArray);
             *     }
             *
             *
             */

            int maxArguments;

            if (ExcelDnaUtil.ExcelVersion >= 12.0)
            {
                maxArguments = 125; // Constrained by 255 char registration string, take off 3 type chars, use up to 2 chars per param (before we start doing object...) (& also return)
                                    // CONSIDER: Might improve this if we generate the delegate based on the max length...
            }
            else
            {
                maxArguments = 29; // Or maybe 30?
            }

            var normalParams     = functionLambda.Parameters.Take(functionLambda.Parameters.Count() - 1).ToList();
            var normalParamCount = normalParams.Count;
            var paramsParamCount = maxArguments - normalParamCount;
            var allParamExprs    = new List <ParameterExpression>(normalParams);
            var blockExprs       = new List <Expression>();
            var blockVars        = new List <ParameterExpression>();

            // Run through the arguments looking for the position of the last non-ExcelMissing argument
            var lastArgVarExpr = Expression.Variable(typeof(int));

            blockVars.Add(lastArgVarExpr);
            blockExprs.Add(Expression.Assign(lastArgVarExpr, Expression.Constant(0)));
            for (int i = normalParamCount + 1; i <= maxArguments; i++)
            {
                allParamExprs.Add(Expression.Parameter(typeof(object), "arg" + i));

                var lenTestParam = Expression.IfThen(Expression.Not(Expression.TypeIs(allParamExprs[i - 1], typeof(ExcelMissing))),
                                                     Expression.Assign(lastArgVarExpr, Expression.Constant(i)));
                blockExprs.Add(lenTestParam);
            }

            // We know that last parameter is an array type
            // Create a new list to hold the values
            var argsArrayType   = functionLambda.Parameters.Last().Type;
            var argsType        = argsArrayType.GetElementType();
            var argsListType    = typeof(List <>).MakeGenericType(argsType);
            var argsListVarExpr = Expression.Variable(argsListType);

            blockVars.Add(argsListVarExpr);
            var argListAssignExpr = Expression.Assign(argsListVarExpr, Expression.New(argsListType));

            blockExprs.Add(argListAssignExpr);
            // And put the (converted) arguments into the list
            for (int i = normalParamCount + 1; i <= maxArguments; i++)
            {
                var testParam = Expression.IfThen(Expression.GreaterThanOrEqual(lastArgVarExpr, Expression.Constant(i)),
                                                  Expression.Call(argsListVarExpr, "Add", null,
                                                                  TypeConversion.GetConversion(allParamExprs[i - 1], argsType)));

                blockExprs.Add(testParam);
            }
            var argArrayVarExpr = Expression.Variable(argsArrayType);

            blockVars.Add(argArrayVarExpr);

            var argArrayAssignExpr = Expression.Assign(argArrayVarExpr, Expression.Call(argsListVarExpr, "ToArray", null));

            blockExprs.Add(argArrayAssignExpr);

            var innerParams = new List <Expression>(normalParams)
            {
                argArrayVarExpr
            };
            var callInner = Expression.Invoke(functionLambda, innerParams);

            blockExprs.Add(callInner);

            var blockExpr = Expression.Block(blockVars, blockExprs);

            // Build the delegate type to return
            var allParamTypes = normalParams.Select(pi => pi.Type).ToList();
            var toAdd         = maxArguments - allParamTypes.Count;

            for (int i = 0; i < toAdd; i++)
            {
                allParamTypes.Add(typeof(object));
            }
            allParamTypes.Add(functionLambda.ReturnType);

            Type delegateType;

            if (maxArguments == 125)
            {
                delegateType = typeof(CustomFunc125 <, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,>)
                               .MakeGenericType(allParamTypes.ToArray());
            }
            else // if (maxArguments == 29)
            {
                delegateType = typeof(CustomFunc29 <, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,>)
                               .MakeGenericType(allParamTypes.ToArray());
            }
            return(Expression.Lambda(delegateType, blockExpr, allParamExprs));
        }