/// <summary> /// Get the return value from an aggregate function. /// </summary> /// <param name="index">Index represents result row number within the grouping, and is used for series functions that return multiple results from one aggregation.</param> /// <returns></returns> public object ReturnValue(int?index = 0) { if (ResultMethod != null) { var outputsCount = Outputs?.Length ?? 0; int indexAdjust; object[] parameters; //if the result method has an "index" as the first parameter, then add the index if (ResultMethod.GetParameters().Any() && ResultMethod.GetParameters()[0].Name == "index") { parameters = new object[outputsCount + 1]; parameters[0] = index; indexAdjust = 1; } else { parameters = new object[outputsCount]; indexAdjust = 0; } List <object> arrayValues = null; for (var i = 0; i < outputsCount; i++) { //FYI: this code will only accommodate for array being last parameter. if (Outputs != null && Outputs[i].IsArray) { if (arrayValues == null) { arrayValues = new List <object>(); } arrayValues.Add(null); } else { parameters[i + indexAdjust] = null; } } if (arrayValues != null) { parameters[outputsCount + indexAdjust] = arrayValues.Select(c => Convert.ChangeType(c, Type.GetType("System." + Outputs.Last().DataType))); } _returnValue = ResultMethod.Invoke(ObjectReference, parameters); var arrayNumber = 0; for (var i = 0; i < outputsCount; i++) { if (Outputs != null && Outputs[i].IsArray) { var array = (object[])parameters[i + indexAdjust]; try { Outputs[i].SetValue(arrayNumber >= array.Length ? DBNull.Value : array[arrayNumber]); } catch (Exception ex) { #if DEBUG throw new AggregateException($"The function {FunctionName} with the output array {Outputs[i].Name} with values {string.Join(",", array)} could not be converted. " + ex.Message, ex); #else throw new AggregateException($"The function {FunctionName} with the output array {Outputs[i].Name} could not be converted. " + ex.Message, ex); #endif } arrayNumber++; } else { try { Outputs[i].SetValue(parameters[i + indexAdjust]); } catch (Exception ex) { #if DEBUG throw new AggregateException($"The function {FunctionName} with the output parameter {Outputs[i].Name} with value {parameters[i + indexAdjust]} could not be converted. " + ex.Message, ex); #else throw new AggregateException($"The function {FunctionName} with the output parameter {Outputs[i].Name} could not be converted. " + ex.Message, ex); #endif } } } } return(_returnValue); }
private void Initialize(object target, MethodInfo functionMethod, TableColumn[] inputMappings, TableColumn targetColumn, TableColumn[] outputMappings) { FunctionMethod = functionMethod; var attribute = functionMethod.GetCustomAttribute <TransformFunctionAttribute>(); var targetType = target.GetType(); // Get the ResetMethod/ResultMethod which are used for aggregatate functions. if (attribute != null) { ResetMethod = string.IsNullOrEmpty(attribute.ResetMethod) ? null : targetType.GetMethod(attribute.ResetMethod); ResultMethod = string.IsNullOrEmpty(attribute.ResultMethod) ? null : targetType.GetMethod(attribute.ResultMethod); ImportMethod = string.IsNullOrEmpty(attribute.ImportMethod) ? null : targetType.GetMethod(attribute.ImportMethod); } ObjectReference = target; TargetColumn = targetColumn; ReturnType = GetTypeCode(FunctionMethod.ReturnType); var inputParameters = functionMethod.GetParameters().Where(c => !c.IsOut).ToArray(); if (inputMappings == null) { inputMappings = new TableColumn[inputParameters.Length]; } Inputs = new Parameter[inputMappings.Length]; var parameterCount = 0; for (var i = 0; i < inputMappings.Length; i++) { if (parameterCount > inputParameters.Length) { throw new Exception("The input parameters could not be intialized as there are " + inputMappings.Length + " input mappings, however the function only has " + inputParameters.Length + " input parameters."); } Inputs[i] = new Parameter { Column = inputMappings[i], Name = inputParameters[parameterCount].Name, IsColumn = true }; var parameterType = inputParameters[parameterCount].ParameterType; Inputs[i].IsArray = parameterType.IsArray; if (parameterType.IsArray) { Inputs[i].DataType = GetTypeCode(parameterType.GetElementType()); } else { Inputs[i].DataType = GetTypeCode(parameterType); } //if (Inputs[i].DataType == ETypeCode.Unknown) //{ // throw new Exception("The datatype: " + inputParameters[i].GetType().ToString() + " for parameter " + inputParameters[i].Name + " is not a supported datatype."); //} //when an array is found in a method, all parameters are mapped to this. if (!parameterType.IsArray) { parameterCount++; } } ParameterInfo[] outputParameters; if (ResultMethod == null) { outputParameters = functionMethod.GetParameters().Where(c => c.IsOut).ToArray(); } else { outputParameters = ResultMethod.GetParameters().Where(c => c.IsOut).ToArray(); } parameterCount = 0; if (outputParameters.Length > 0) { Outputs = new Parameter[outputParameters.Length]; if (outputMappings == null) { outputMappings = new TableColumn[outputParameters.Length]; } for (var i = 0; i < outputMappings.Length; i++) { if (parameterCount > inputParameters.Length) { throw new Exception("The output parameters could not be intialized as there are " + outputMappings.Length + " output mappings, however the function only has " + outputParameters.Length + " output parameters."); } Outputs[i] = new Parameter { Column = outputMappings[i], Name = outputParameters[parameterCount].Name }; var parameterType = outputParameters[parameterCount].ParameterType.GetElementType(); Outputs[i].IsArray = parameterType.IsArray; if (parameterType.IsArray) { Outputs[i].DataType = GetTypeCode(parameterType.GetElementType()); } else { Outputs[i].DataType = GetTypeCode(parameterType); } //if (Outputs[i].DataType == ETypeCode.Unknown) //{ // throw new Exception("The datatype: " + outputParameters[i].GetType().ToString() + " for parameter " + outputParameters[i].Name + " is not a supported datatype."); //} //when an array is found in a method, all parameters are mapped to this. if (!parameterType.IsArray) { parameterCount++; } } } }