Ejemplo n.º 1
0
        public async Task <object> Calcualte(ExpressionCalculator calculator, string expression, object executeContext)
        {
            if (string.IsNullOrEmpty(expression))
            {
                var fragment = new TextFragment()
                {
                    Code = TextCodes.ExpressionEmptyInExpressionCalculatorByName,
                    DefaultFormatting = "在名称为{0}的表达式计算器中,要计算的表达式为空",
                    ReplaceParameters = new List <object>()
                    {
                        calculator.Name
                    }
                };

                throw new UtilityException((int)Errors.ExpressionEmptyInExpressionCalculatorByName, fragment);
            }

            //公式的正则表达式
            Regex reg = new Regex(@"\{(?<!\\)\$[A-Za-z0-9]((?!(\{(?<!\\)\$[A-Za-z0-9][A-Za-z0-9_]+\(.*\)(?<!\\)\})).)+?(?<!\\)\}");
            //公式参数_ref的正则表达式
            Regex regRefExpression = new Regex(@"(?<!\\)\$_ref\((.*)\)");
            ///公式参数_ref的参数的正则表达式
            //Regex regRefParameterExpression = new Regex(@"(?<=\$_ref\().*(?=\))");

            ConcurrentDictionary <string, object> dictValues = new ConcurrentDictionary <string, object>();

            while (true)
            {
                //通过正则表达式获取公式参数
                var matchs = reg.Matches(expression);
                int length = matchs.Count;

                if (length == 0)
                {
                    break;
                }

                var matchList = matchs.Cast <Match>();


                ConcurrentDictionary <int, string> dictResult = new ConcurrentDictionary <int, string>();

                Dictionary <string, Semaphore> lockObjs = new Dictionary <string, Semaphore>();

                if (calculator.FormulaExecuteParallelism > 1)
                {
                    //生成锁定对象集
                    foreach (var item in matchList)
                    {
                        lockObjs[item.Value] = new Semaphore(1, 1);
                    }
                }

                //设定并行计算

                await ParallelHelper.ForEach <Match>(matchList, calculator.FormulaExecuteParallelism, async (match) =>
                {
                    //获取公式

                    var formula = getFormulaCalculator(calculator, match.Value);

                    var formulaService = getFormulaCalculateService(calculator.Name, formula.Name);

                    //检查公式参数,如果参数格式为$_ref(XXX),则值从dictValues中获取,
                    //如果为一般字符串,则需调用对应公式服务的ParameterConvert方法来获取实际值

                    List <object> formulaParameters = new List <object>();

                    for (var index = 0; index <= formula.ParameterExpressions.Count - 1; index++)
                    {
                        var peMatch = regRefExpression.Match(formula.ParameterExpressions[index]);
                        if (peMatch.Success)
                        {
                            if (!dictValues.TryGetValue(peMatch.Groups[1].Value, out object pValue))
                            {
                                var fragment = new TextFragment()
                                {
                                    Code = TextCodes.NotFoundValueInExpressionStoreValues,
                                    DefaultFormatting = "在名称为{0}的表达式计算器中,找不到键为{1}的值,表达式为{2}",
                                    ReplaceParameters = new List <object>()
                                    {
                                        calculator.Name, peMatch.Groups[1].Value, peMatch.Value
                                    }
                                };

                                throw new UtilityException((int)Errors.NotFoundValueInExpressionStoreValues, fragment);
                            }

                            formulaParameters.Add(pValue);
                        }
                        else
                        {
                            formulaParameters.Add(await formulaService.ParameterConvert(index, formula.ParameterExpressions[index].Replace(@"\}", "}").Replace(@"\$", "$").Replace(@"\,", ",").Replace(@"\\", @"\")));
                        }
                    }

                    //判断是否可重复使用
                    //如果可重复使用,则通过公式名称存储
                    //如果不可重复使用,则通过guid作为名称存储
                    if (await formulaService.IsIndividual())
                    {
                        if (!dictValues.TryGetValue(formula.Name, out object value))
                        {
                            try
                            {
                                if (calculator.FormulaExecuteParallelism > 1)
                                {
                                    lockObjs[match.Value].WaitOne();
                                }
                                if (!dictValues.TryGetValue(formula.Name, out value))
                                {
                                    //计算公式
                                    var formulaValue         = await formulaService.Calculate(formulaParameters, executeContext);
                                    dictValues[formula.Name] = formulaValue;
                                }
                            }
                            finally
                            {
                                if (calculator.FormulaExecuteParallelism > 1)
                                {
                                    lockObjs[match.Value].Release();
                                }
                            }
                        }

                        dictResult[match.Index] = string.Format(@"$_ref({0})", formula.Name);
                    }
                    else
                    {
                        //计算公式
                        var formulaValue                  = await formulaService.Calculate(formulaParameters, executeContext);
                        string calculatedFormulaName      = Guid.NewGuid().ToString();
                        dictValues[calculatedFormulaName] = formulaValue;
                        dictResult[match.Index]           = string.Format(@"$_ref({0})", calculatedFormulaName);
                    }
                });

                //为每个匹配项做替换
                expression = reg.Replace(expression, (match) =>
                {
                    if (dictResult.TryGetValue(match.Index, out string matchResult))
                    {
                        return(matchResult);
                    }
                    else
                    {
                        return(match.Value);
                    }
                });
            }

            //content = content.Replace(@"\}", "}").Replace(@"\$", "$").Replace(@"\,", ",").Replace(@"\\", @"\");

            var lastMatch = regRefExpression.Match(expression);

            if (!lastMatch.Success)
            {
                var fragment = new TextFragment()
                {
                    Code = TextCodes.ExpressionFormatError,
                    DefaultFormatting = "在名称为{0}的表达式计算器中,表达式格式不正确,表达式为{1}",
                    ReplaceParameters = new List <object>()
                    {
                        calculator.Name, expression
                    }
                };

                throw new UtilityException((int)Errors.ExpressionFormatError, fragment);
            }

            if (!dictValues.TryGetValue(lastMatch.Groups[1].Value, out object value))
            {
                var fragment = new TextFragment()
                {
                    Code = TextCodes.NotFoundValueInExpressionStoreValues,
                    DefaultFormatting = "在名称为{0}的表达式计算器中,找不到键为{1}的值,表达式为{2}",
                    ReplaceParameters = new List <object>()
                    {
                        calculator.Name, lastMatch.Groups[1].Value, expression
                    }
                };

                throw new UtilityException((int)Errors.NotFoundValueInExpressionStoreValues, fragment);
            }

            return(value);
        }