public static GetConversion ( |
||
input | ||
type | ||
return |
static LambdaExpression OptionalConversion(Type type, ExcelParameterRegistration paramReg, bool treatEmptyAsMissing, bool treatNAErrorAsMissing) { // Decide whether to return a conversion function for this parameter if (!paramReg.CustomAttributes.OfType <OptionalAttribute>().Any()) { return(null); } var defaultAttribute = paramReg.CustomAttributes.OfType <DefaultParameterValueAttribute>().FirstOrDefault(); var defaultValue = defaultAttribute == null?TypeConversion.GetDefault(type) : defaultAttribute.Value; // var returnType = type.GetGenericArguments()[0]; // E.g. returnType is double // Consume the attributes paramReg.CustomAttributes.RemoveAll(att => att is OptionalAttribute); paramReg.CustomAttributes.RemoveAll(att => att is DefaultParameterValueAttribute); // Here's the actual conversion function var input = Expression.Parameter(typeof(object), "input"); return (Expression.Lambda( Expression.Condition( MissingTest(input, treatEmptyAsMissing, treatNAErrorAsMissing), Expression.Constant(defaultValue, type), TypeConversion.GetConversion(input, type)), input)); }
internal static LambdaExpression NullableConversion( ParameterConversionConfiguration config, Type type, ExcelParameterRegistration paramReg, bool treatEmptyAsMissing, bool treatNAErrorAsMissing) { // Decide whether to return a conversion function for this parameter if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Nullable <>)) { return(null); } var innerType = type.GetGenericArguments()[0]; // E.g. innerType is Complex LambdaExpression innerTypeConversion = ParameterConversionRegistration.GetParameterConversion(config, innerType, paramReg) ?? TypeConversion.GetConversion(typeof(object), innerType); ParameterExpression input = innerTypeConversion.Parameters[0]; // Here's the actual conversion function var result = Expression.Lambda( Expression.Condition( // if the value is missing (or possibly empty) MissingTest(input, treatEmptyAsMissing, treatNAErrorAsMissing), // cast null to int? Expression.Constant(null, type), // else convert to int, and cast that to int? Expression.Convert(Expression.Invoke(innerTypeConversion, input), type)), input); return(result); }
internal static LambdaExpression NullableConversion( IEnumerable <ParameterConversionConfiguration.ParameterConversion> parameterConversions, Type type, ExcelParameterRegistration paramReg, bool treatEmptyAsMissing, bool treatNAErrorAsMissing) { // Decide whether to return a conversion function for this parameter if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Nullable <>)) { return(null); } var innerType = type.GetGenericArguments()[0]; // E.g. innerType is Complex // Try to find a converter for innerType in the config ParameterConversionConfiguration.ParameterConversion innerTypeParameterConversion = null; if (parameterConversions != null) { innerTypeParameterConversion = parameterConversions.FirstOrDefault(c => c.Convert(innerType, paramReg) != null); } ParameterExpression input = null; Expression innerTypeConversion = null; // if we have a converter for innertype in the config, then use it. Otherwise try one of the conversions for the basic types if (innerTypeParameterConversion == null) { input = Expression.Parameter(typeof(object), "input"); innerTypeConversion = TypeConversion.GetConversion(input, innerType); } else { var innerTypeParamConverter = innerTypeParameterConversion.Convert(innerType, paramReg); input = Expression.Parameter(innerTypeParamConverter.Parameters[0].Type, "input"); innerTypeConversion = Expression.Invoke(innerTypeParamConverter, input); } // Here's the actual conversion function var result = Expression.Lambda( Expression.Condition( // if the value is missing (or possibly empty) MissingTest(input, treatEmptyAsMissing, treatNAErrorAsMissing), // cast null to int? Expression.Constant(null, type), // else convert to int, and cast that to int? Expression.Convert(innerTypeConversion, type)), input); return(result); }
// Implementations static LambdaExpression NullableConversion(Type type, ExcelParameterRegistration paramReg, bool treatEmptyAsMissing) { // Decide whether to return a conversion function for this parameter if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Nullable <>)) // E.g. type is Nullable<double> { return(null); } var innerType = type.GetGenericArguments()[0]; // E.g. innerType is double // Here's the actual conversion function var input = Expression.Parameter(typeof(object)); var result = Expression.Lambda( Expression.Condition( // if the value is missing (or possibly empty) MissingTest(input, treatEmptyAsMissing), // cast null to int? Expression.Constant(null, type), // else convert to int, and cast that to int? Expression.Convert(TypeConversion.GetConversion(input, innerType), type)), input); return(result); }
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 arg1, object arg2, object arg3, object arg4, {...until...}, object arg253) * { * List<object> args = new List<object>(); * if (!(arg1 is ExcelMissing)) args.Add(arg1); * if (!(arg2 is ExcelMissing)) args.Add(arg2); * ... * if (!(arg253 is ExcelMissing)) args.Add(arg253); * * 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 paramsParamExprs = new List <ParameterExpression>(normalParams); var blockExprs = new List <Expression>(); var blockVars = new List <ParameterExpression>(); // We know that last parameter is an array type 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); for (int i = 1; i <= paramsParamCount; i++) { var paramExpr = Expression.Parameter(typeof(object), "arg" + i); paramsParamExprs.Add(paramExpr); var testParam = Expression.IfThen(Expression.Not(Expression.TypeIs(paramExpr, typeof(ExcelMissing))), Expression.Call(argsListVarExpr, "Add", null, TypeConversion.GetConversion(paramExpr, 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, paramsParamExprs)); }
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)); }