Adding var args support to office integration functions with dynamic lambda expressions

Anyone who’s ever done office integration has come across a method definition like so:

object Run(object Macro, object Arg1, object Arg2, …, object Arg30);

if you're working in VB it’s not such an issue, and rumor has it that it’s that C# 4 will also solve the problem of code such as:

Run(“…”, Type.Missing, Type.Missing,/*28 more times*/ …, Type.Missing);

But for everyone else, you can avoid the extra typing with an extension method and dynamic lambda expressions. For example with:

    public static class OfficeHelpers
    {
        private static MemberInfo missingMemberInfo = typeof(Type).GetMembers().Where(mi => mi.Name == "Missing").Single();
        private static MethodInfo runMethodInfo = typeof(_Application).GetMethod("Run");
        private static ParameterExpression macroNameParamExp = Expression.Parameter(typeof(string), "macroName");
        private static ParameterExpression argsParamExp = Expression.Parameter(typeof(object[]), "args");

        public static object Run(this Application App, string macroName, params object[] args)
        {
            var argsExprs = GenerateArgs(runMethodInfo, macroName, args);
            var callExpr = Expression.Call(Expression.Constant(App), runMethodInfo, argsExprs);
            var paramExprs = new ParameterExpression[] { macroNameParamExp, argsParamExp };
            var lambda = Expression.Lambda>(callExpr, paramExprs);
            return lambda.Compile().Invoke(macroName, args);
        }

        private static IEnumerable<Expression> GenerateArgs(MethodInfo runfuncMI, string macroName, object[] args)
        {
            yield return macroNameParamExp;
            for (int ii = 0; ii < args.Length; ii++)
                yield return BinaryExpression.ArrayIndex(argsParamExp, Expression.Constant(ii, typeof(int)));
            for (int ii = 0; ii < runfuncMI.GetParameters().Length - args.Length - 1; ii++)
                yield return Expression.MakeMemberAccess(null, missingMemberInfo);
        }

a call to

OfficeHelpers.Run("…", arg1,arg2,arg3);

will generate and execute an expression like so:

(macroName, args) => RunFuncTest(macroName, args[0], args[1], args[2], Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing)

No Comments