【问题标题】:Pars Text or script into C# code将文本或脚本解析为 C# 代码
【发布时间】:2012-01-17 21:36:59
【问题描述】:

我想将方法​​调用和公式的组合作为文本或脚本存储到数据库中。例如,我想将这样的内容作为字符串存储在数据库中并在代码中的某处执行:

if(Vessel.Weight>200) 
{
    return Cargo.Weight*Cargo.Tariff*2
} 
else 
{
    Cargo.Weight*Cargo.Tariff
} 

调用:

var cost = executeFormula("CalculateTariff",new {Cargo= GetCargo(), Vessel=GetVessel()});

因为这些规则会经常更改,我不想部署 dll(CLR 解决方案),我不想将这些规则存储为 SP 并将业务规则与 DAL 混合。

有什么想法或工具吗?

【问题讨论】:

  • @jmacinnes:我应该在我的代码中将脚本作为命令执行:var cost = executeFormula("CalculateTariff",new {Cargo= GetCargo(), Vessel=GetVessel()});跨度>

标签: c# parsing


【解决方案1】:

如果您通过更改 .使用 _ (Vessel.Weight 将变为“Vessel_Weight”)并将语法简化为一行,创建解决方案会容易得多。例如,这条规则可以写成:

result=(Vessel_Weight>200)
    ?(Cargo_Weight*Cargo_Tariff*2)
    :(Cargo_Weight*Cargo_Tariff)

像上面那样定义规则后,您可以使用以下(草稿,不是最佳...)代码作为正确编码功能的指南,以完成这项工作。我再说一遍,下面的代码并不完美,但最重要的是,它作为概念证明已经绰绰有余了。

Dictionary<string, dynamic> compute = new Dictionary<string, dynamic>();
compute.Add("Vessel_Weight", 123);
compute.Add("Cargo_Weight", 24);
compute.Add("Cargo_Tariff", 9);

    string rule = "result=(Vessel_Weight>200)
        ?(Cargo_Weight*Cargo_Tariff*2)
        :(Cargo_Weight*Cargo_Tariff)";

    string process = rule.Replace(" ", "");
    foreach (Match level1 in Regex.Matches(process, "\\([^\\)]+\\)"))
    {
        string parenthesis = level1.Value;
        string keepit = parenthesis;
        Console.Write("{0} -> ", parenthesis);
        // replace all named variable with values from the dictionary
        foreach (Match level2 in Regex.Matches(parenthesis, "[a-zA-z0-9_]+"))
        {
            string variable = level2.Value;
            if (Regex.IsMatch(variable, "[a-zA-z_]+"))
            {
                if (!compute.ContainsKey(variable))
                    throw new Exception("Variable not found");
                parenthesis = parenthesis.Replace(variable, compute[variable].ToString());
            }
        }
        parenthesis = parenthesis.Replace("(", "").Replace(")", "");
        Console.Write("{0} -> ", parenthesis);
        // do the math
        List<double> d = new List<double>();
        foreach (Match level3 in Regex.Matches(parenthesis, "[0-9]+(\\.[0-9]+)?"))
        {
            d.Add(double.Parse(level3.Value));
            parenthesis = Regex.Replace(parenthesis, level3.Value, "");
        }
        double start = d[0];
        for (var i = 1; i < d.Count; i++)
        {
            switch (parenthesis[i - 1])
            {
                case '+':
                    start += d[i];
                    break;
                case '-':
                    start -= d[i];
                    break;
                case '*':
                    start *= d[i];
                    break;
                case '/':
                    start /= d[i];
                    break;
                case '=':
                    start = (start == d[i]) ? 0 : 1;
                    break;
                case '>':
                    start = (start > d[i]) ? 0 : 1;
                    break;
                case '<':
                    start = (start < d[i]) ? 0 : 1;
                    break;
            }
        }
        parenthesis = start.ToString();
        Console.WriteLine(parenthesis);
        rule = rule.Replace(keepit, parenthesis);
    }
    Console.WriteLine(rule);
    // peek a value in case of a condition
    string condition = "[0-9]+(\\.[0-9]+)?\\?[0-9]+(\\.[0-9]+)?:[0-9]+(\\.[0-9]+)?";
    if (Regex.IsMatch(rule, condition))
    {
        MatchCollection m = Regex.Matches(rule, "[0-9]+(\\.[0-9]+)?");
        int check = int.Parse(m[0].Value) + 1;
        rule = rule.Replace(Regex.Match(rule, condition).Value, m[check].Value);
    }
    Console.WriteLine(rule);
    // final touch
    int equal = rule.IndexOf("=");
    compute.Add(rule.Substring(0, equal - 1), double.Parse(rule.Substring(equal + 1)));

现在结果是字典中的一个命名项。这样,您可以在中间结果的意义上处理更多规则,并基于它们制定最终规则。编写的代码不能保证算术运算的正确执行顺序,但是如果您保持规则简单(如果需要,可能会拆分它们),您将实现您的目标。

【讨论】:

  • 实际上这是我的计划,但我的老板说不要编写解析器,而是使用解析器。我不同意这个想法,因为请考虑一下安全性!数据库和服务器中的用户代码运行它。我再也睡不着了。
  • 有一个解决方案可以让您和您的老板都满意:将规则存储在数据库中(为您的老板)并编写一个解析器(为您):) 如果您最终决定编写一个解析器遵循不同的模式来定义规则(类似于基本的 excel 函数),这将大大简化解析(即 MUL(Cargo_Weight,Cargo_Tariff))
猜你喜欢
  • 1970-01-01
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 1970-01-01
  • 2011-11-17
  • 2021-10-10
  • 2013-03-13
相关资源
最近更新 更多