static bool IsParamsMethod(ExcelFunctionRegistration reg) { var lastParam = reg.ParameterRegistrations.LastOrDefault(); return(lastParam != null && lastParam.CustomAttributes.Any(att => att is ParamArrayAttribute) && reg.FunctionLambda.Parameters.Last().Type.IsArray); }
internal static FunctionExecutionHandler TimingHandlerSelector(ExcelFunctionRegistration functionRegistration) { // Eat the TimingAttributes, and return a timer handler if there were any if (functionRegistration.CustomAttributes.RemoveAll(att => att is TimingAttribute) == 0) { // No attributes return null; } return _handler.Value; }
static void ApplyMethodHandlers(ExcelFunctionRegistration reg, IEnumerable <IFunctionExecutionHandler> handlers) { // The order of method handlers is important - we follow PostSharp's convention for MethodExecutionHandlers. // They are passed from high priority (most inside) to low priority (most outside) // Imagine 2 FunctionHandlers, fh1 then fh2 // So fh1 (highest priority) will be 'inside' and fh2 will be outside (lower priority) foreach (var handler in handlers) { reg.FunctionLambda = ApplyMethodHandler(reg.FunctionAttribute.Name, reg.FunctionLambda, handler); } }
/////////////////////// Registration handler ////////////////////////////////// // (This code can be anywhere... - need not be in this class) // In this case, we only ever make one 'handler' object public static FunctionExecutionHandler CacheHandlerSelector(ExcelFunctionRegistration functionRegistration) { // Eat the TimingAttributes, and return a timer handler if there were any if (functionRegistration.CustomAttributes.OfType<CacheAttribute>().Any()) { // Get the first cache attribute, and remove all of them var cacheAtt = functionRegistration.CustomAttributes.OfType<CacheAttribute>().First(); functionRegistration.CustomAttributes.RemoveAll(att => att is CacheAttribute); return new CacheFunctionExecutionHandler(cacheAtt.CacheTimeout); } return null; }
public static void TestInstanceRegistration() { var instanceMethod = typeof(TestClass).GetMethod("GetContent"); var lambda = WrapInstanceMethod(instanceMethod); // Create a new object every time the instance method is called... (typically we'd look up using a handle) var paramConversionConfig = new ParameterConversionConfiguration() .AddParameterConversion((string content) => new TestClass(content)); // TODO: Clean up how we suggest this code gets called var reg = new ExcelFunctionRegistration(lambda); var processed = ParameterConversionRegistration.ProcessParameterConversions(new[] { reg }, paramConversionConfig); processed.RegisterFunctions(); }
/// <summary> /// Currently only applied to functions that return object or string. /// </summary> /// <param name="functionRegistration"></param> /// <returns></returns> public static IFunctionExecutionHandler SuppressInDialogSelector(ExcelFunctionRegistration functionRegistration) { // Eat the TimingAttributes, and return a timer handler if there were any if (functionRegistration.CustomAttributes.OfType <SuppressInDialogAttribute>().Any() && (functionRegistration.FunctionLambda.ReturnType == typeof(object) || functionRegistration.FunctionLambda.ReturnType == typeof(string))) { // Get the first cache attribute, and remove all of them var suppressAtt = functionRegistration.CustomAttributes.OfType <SuppressInDialogAttribute>().First(); functionRegistration.CustomAttributes.RemoveAll(att => att is SuppressInDialogAttribute); return(suppressAtt); } return(null); }
/// <summary> /// Currently only applied to functions that return object or string. /// </summary> /// <param name="functionRegistration"></param> /// <returns></returns> public static IFunctionExecutionHandler SuppressInDialogSelector(ExcelFunctionRegistration functionRegistration) { // Eat the TimingAttributes, and return a timer handler if there were any if (functionRegistration.CustomAttributes.OfType<SuppressInDialogAttribute>().Any() && (functionRegistration.FunctionLambda.ReturnType == typeof(object) || functionRegistration.FunctionLambda.ReturnType == typeof(string))) { // Get the first cache attribute, and remove all of them var suppressAtt = functionRegistration.CustomAttributes.OfType<SuppressInDialogAttribute>().First(); functionRegistration.CustomAttributes.RemoveAll(att => att is SuppressInDialogAttribute); return suppressAtt; } return null; }
static void ApplyMethodHandlers(ExcelFunctionRegistration reg, IEnumerable<IFunctionExecutionHandler> handlers) { // The order of method handlers is important - we follow PostSharp's convention for MethodExecutionHandlers. // They are passed from high priority (most inside) to low priority (most outside) // Imagine 2 FunctionHandlers, fh1 then fh2 // So fh1 (highest priority) will be 'inside' and fh2 will be outside (lower priority) foreach (var handler in handlers) { reg.FunctionLambda = ApplyMethodHandler(reg.FunctionAttribute.Name, reg.FunctionLambda, handler); } }
internal static FunctionExecutionHandler LoggingHandlerSelector(ExcelFunctionRegistration functionRegistration) { return new FunctionLoggingHandler { Index = _index++ }; }
static bool IsParamsMethod(ExcelFunctionRegistration reg) { var lastParam = reg.ParameterRegistrations.LastOrDefault(); return lastParam != null && lastParam.CustomAttributes.Any(att => att is ParamArrayAttribute) && reg.FunctionLambda.Parameters.Last().Type.IsArray; }
// returnsConversion and the entries in paramsConversions may be null. static void ApplyConversions(ExcelFunctionRegistration reg, List <List <LambdaExpression> > paramsConversions, List <LambdaExpression> returnConversions) { // CAREFUL: The parameter transformations are applied in reverse order to how they're identified. // We do the following transformation // public static string dnaParameterConvertTest(double? optTest) { }; // // with conversions convert1 and convert2 taking us from Type1 to double? // // to // public static string dnaParameterConvertTest(Type1 optTest) // { // return convertRet2(convertRet1( // dnaParameterConvertTest( // paramConvert1(optTest) // ))); // }; // // and then with a conversion from object to Type1, resulting in // // public static string dnaParameterConvertTest(object optTest) // { // return convertRet2(convertRet1( // dnaParameterConvertTest( // paramConvert1(paramConvert2(optTest)) // ))); // }; Debug.Assert(reg.FunctionLambda.Parameters.Count == paramsConversions.Count); // NOTE: To cater for the Range COM type equivalance, we need to distinguish the FunctionLambda's parameter type and the paramConversion ReturnType. // These need not be the same, but the should at least be equivalent. // build up the invoke expression for each parameter var wrappingParameters = reg.FunctionLambda.Parameters.Select(p => Expression.Parameter(p.Type, p.Name)).ToList(); // Build the nested parameter convertion expression. // Start with the wrapping parameters as they are. Then replace with the nesting of conversions as needed. var paramExprs = new List <Expression>(wrappingParameters); for (int i = 0; i < paramsConversions.Count; i++) { var paramConversions = paramsConversions[i]; if (paramConversions == null) { continue; } // If we have a list, there should be at least one conversion in it. Debug.Assert(paramConversions.Count > 0); // Update the calling parameter type to be the outer one in the conversion chain. wrappingParameters[i] = Expr.Parameter(paramConversions.Last().Parameters[0].Type, wrappingParameters[i].Name); // Start with just the (now updated) outer param which will be the inner-most value in the conversion chain Expression wrappedExpr = wrappingParameters[i]; // Need to go in reverse for the parameter wrapping // Need to now build from the inside out foreach (var conversion in Enumerable.Reverse(paramConversions)) { wrappedExpr = Expr.Invoke(conversion, wrappedExpr); } paramExprs[i] = wrappedExpr; } var wrappingCall = Expr.Invoke(reg.FunctionLambda, paramExprs); if (returnConversions != null) { foreach (var conversion in returnConversions) { wrappingCall = Expr.Invoke(conversion, wrappingCall); } } reg.FunctionLambda = Expr.Lambda(wrappingCall, reg.FunctionLambda.Name, wrappingParameters); }
// returnsConversion and the entries in paramsConversions may be null. static void ApplyConversions(ExcelFunctionRegistration reg, List<List<LambdaExpression>> paramsConversions, List<LambdaExpression> returnConversions) { // CAREFUL: The parameter transformations are applied in reverse order to how they're identified. // We do the following transformation // public static string dnaParameterConvertTest(double? optTest) { }; // // with conversions convert1 and convert2 taking us from Type1 to double? // // to // public static string dnaParameterConvertTest(Type1 optTest) // { // return convertRet2(convertRet1( // dnaParameterConvertTest( // paramConvert1(optTest) // ))); // }; // // and then with a conversion from object to Type1, resulting in // // public static string dnaParameterConvertTest(object optTest) // { // return convertRet2(convertRet1( // dnaParameterConvertTest( // paramConvert1(paramConvert2(optTest)) // ))); // }; Debug.Assert(reg.FunctionLambda.Parameters.Count == paramsConversions.Count); // NOTE: To cater for the Range COM type equivalance, we need to distinguish the FunctionLambda's parameter type and the paramConversion ReturnType. // These need not be the same, but the should at least be equivalent. // build up the invoke expression for each parameter var wrappingParameters = reg.FunctionLambda.Parameters.Select(p => Expression.Parameter(p.Type, p.Name)).ToList(); // Build the nested parameter convertion expression. // Start with the wrapping parameters as they are. Then replace with the nesting of conversions as needed. var paramExprs = new List<Expression>(wrappingParameters); for (int i = 0; i < paramsConversions.Count; i++) { var paramConversions = paramsConversions[i]; if (paramConversions == null) continue; // If we have a list, there should be at least one conversion in it. Debug.Assert(paramConversions.Count > 0); // Update the calling parameter type to be the outer one in the conversion chain. wrappingParameters[i] = Expr.Parameter(paramConversions.Last().Parameters[0].Type, wrappingParameters[i].Name); // Start with just the (now updated) outer param which will be the inner-most value in the conversion chain Expression wrappedExpr = wrappingParameters[i]; // Need to go in reverse for the parameter wrapping // Need to now build from the inside out foreach (var conversion in Enumerable.Reverse(paramConversions)) { wrappedExpr = Expr.Invoke(conversion, wrappedExpr); } paramExprs[i] = wrappedExpr; } var wrappingCall = Expr.Invoke(reg.FunctionLambda, paramExprs); if (returnConversions != null) { foreach (var conversion in returnConversions) wrappingCall = Expr.Invoke(conversion, wrappingCall); } reg.FunctionLambda = Expr.Lambda(wrappingCall, reg.FunctionLambda.Name, wrappingParameters); }