设计帮助:使用在运行时解析的表达式计算时间

时间:2014-02-17 09:42:20

标签: c# .net sql-server-2008 database-design expression-evaluation

我在数据库中有一些列包含HH:MM格式的时间。现在,如果有像11:00 - 12:00这样的简单表达式,那么我可以轻松地在C#中创建一个名为SubtractTime的扩展方法,并在运行时传递我的参数。我将我的公式存储在数据库中,例如:

Condition                     Value
ExamTimeRemaing > 10:00       SubtractTime(Original,Remaining)     

现在在上面的例子中,我可以在运行时使用反射调用我的SubtractTime函数,但是我的问题是这样,如果我的表达式变得复杂如下:

10:00 + 12:00 * 00:02 - 10:11

我如何解析这些表达式?我不需要编码方面的帮助,因为我已经有了将时间转换为刻度然后转换为HH:MM的扩展。这更像是一个设计问题。我想要一个可扩展的解决方案,以便我可以有效地创建规则引擎。

3 个答案:

答案 0 :(得分:0)

我想说将它存储为字符串并找到运算符。创建一个递归函数ParseAndCalc(字符串输入),它以正确的顺序解析和计算结果。像这样:

double ParseAndCalc(string input)
{
    string[] sub;
    double result = 0;
    if(input.Contains("+"))
    {
        sub = input.Split('+');
        foreach(string substring in sub)
        {
            result += ParseAndCalc(substring);
        }
    }
    else if (input.Contains("-"))
    {
        sub = input.Split('-');
        foreach(string substring in sub)
        {
            result -= ParseAndCalc(substring);
        }
    }
    else if (input.Contains("*"))
    {
        sub = input.Split('*');
        foreach(string substring in sub)
        {
            result *= ParseAndCalc(substring);
        }
    }
    else if (input.Contains("/"))
    {
        sub = input.Split('/');
        foreach(string substring in sub)
        {
            double parsed = ParseAndCalc(substring);
            if(parsed != 0)
            {
                result /= ParseAndCalc(substring);
            }
            else
            {
                // Error
            }
        }
    }
    return result;
}

答案 1 :(得分:0)

首先,您必须考虑开发和维护开销。使用Antlr等创建表达式解析器是绝对荒谬的,我会使用像Jurassic这样的JavaScript引擎或任何其他基于.NET的简单JavaScript引擎这样的现成解决方案。

SQL存储过程/用户定义函数

此外,如果您的规则存储在数据库本身中,那么您可以使用SQL本身的功能来解析和计算表达式,而不是使用解析器。您可以动态组合SQL表达式并传递参数。或者创建存储过程或用户定义的函数,这些函数经过良好测试,众所周知且可扩展,并且保持在数据库的上下文中。

开源.NET JavaScript引擎

您仍然可以使用JavaScript格式将公式存储在数据库中,首先,JavaScript是众所周知的,易于理解并且能够处理复杂的表达式。有许多免费且稳定的JavaScript引擎,它提供丰富的语言功能,您仍然可以在公式中使用现有的JavaScript库。例如,将来你需要Base64,你只需从一些github获取Base64并将它放在你的JavaScript中。

C#编译器

CSharpCompilerProvider类为您提供了一种将C#源编译成程序集的方法,我要做的是使用一些文本模板创建源文件,在SQL中编译和存储程序集以及formulat,当我需要调用表达式时,我可以获取编译版本,使用Assembly.Load加载它并创建具有一些接口并调用它的方法的解析类。 .NET将编译并为您提供程序集,您可以将其作为varbinary(max)存储在数据库中。

答案 2 :(得分:0)

这里的答案告诉你如何做得这么好。如果你决定尝试这个,我可能会自己选择ANTLR路线。

那就是说,我会认真思考为什么要这样做。你提到你正在建立一个“规则引擎”。从这里开始,我假设您有一个数据库或者您想要将一堆业务逻辑存储为“规则”的东西,然后让“规则引擎”读取这个并将其应用于某些数据。作为其中的一部分,您希望某种表达式解析器能够解析和评估某些类型的规则。

在查看这样的设计时,我会小心不要混淆解析规则和执行它们的问题。您可以使用XML,JSON或您喜欢的任何内容格式对规则进行编码。如果这样做,您根本不必编写解析器。你只需评估表达式。

var myRule = [
  { $value: '10:00' },
  { $add: '12:00' },
  { $multiply: 2 },
  { $subtract: '10:11' }
]