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;
 }
Exemple #3
0
 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;
 }
Exemple #11
0
        // 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);
        }