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

C# 设计帮助:使用运行时解析的表达式计算时间,c#,.net,sql-server-2008,database-design,expression-evaluation,C#,.net,Sql Server 2008,Database Design,Expression Evaluation,我在数据库中有一些列包含h:MM格式的时间。现在,如果有像11:00-12:00这样的简单表达式,那么我可以很容易地在C中创建一个名为SubtractTime的扩展方法,并在运行时传递参数。我将在数据库中存储我的公式,例如: Condition Value ExamTimeRemaing > 10:00 SubtractTime(Original,Remaining) 现在在上面的例子中,我可以在运行时使用反射调用Subtra

我在数据库中有一些列包含h: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的扩展。这更像是一个设计问题。我想要一个可扩展的解决方案,这样我就可以高效地创建一个规则引擎。

我想说的是,将其存储为字符串并查找操作符。制作一个递归函数ParseAndCalcstring input,该函数按正确的顺序解析和计算结果。大概是这样的:

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;
}

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

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

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

开源.NETJavaScript引擎

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

C编译器


CSharpCompilerProvider类提供了一种将C源代码编译成程序集的方法,我要做的是使用一些文本模板创建一个源文件,编译并将程序集与formulat一起存储在SQL中,当我需要调用表达式时,我可以获取编译后的版本,使用Assembly.load加载并创建具有某些接口的已解析类,并调用其方法。NET将编译并为您提供程序集,您可以将其作为varbinarymax存储在数据库中。

这里的答案告诉您如何充分做到这一点。如果你决定尝试这个,我可能会自己选择ANTLR路线

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

在研究这样的设计时,我会小心不要混淆解析规则和执行规则的问题。您可能可以用XML、JSON或任何您喜欢的内容格式对规则进行编码。如果这样做,就根本不需要编写解析器。您只需计算表达式

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

12:00*00:02的结果到底是什么?这是一个典型的词法分析器问题。我强烈建议大家阅读一下什么是lexer和grammer。Antlr和gold parser是很好的起点。HH-MM的乘法需要像@PaulZahra提到的那样详细说明,这是Stefan建议的+1的实际应用。您正在谈论创建您自己的DSL,我建议Antlr自己围绕您所寻找的内容创建您自己的语法。更多的工作,但它将是最稳定和灵活的。我可能误读了,但你似乎在说运算符的优先顺序是乘法之前的加法和减法?它应该是12:00*00:02,然后向左+向右-。例如,使用括号来说明正确的顺序:10+12*2/60-10.1833333您是对的,我会更正它。我没有真正注意实际的计算,因为时间乘以时间是很奇怪的。这个概念很好。嗯,我个人不会说这是一个好概念,除非它是一个时间机器或黑客让我的工作时间看起来更长:我从来没有听说过将小时乘以分钟,我请OP详细说明。编辑:如果你指的是计算器中的好概念,DataTables有一个计算方法。eg var十一=新的DataTable.Compute2+3*3;我指的是使用递归函数的概念。我不知道乘时间是什么意思。我想这是故意的
是2而不是00:02,OP没有注意示例的细节。至少可以说,你可以同样假设00:02意味着2分钟*12:00,也就是12*60分钟=720,因此720 x 2。。。。假设下午12:00是午夜12:00,假设24:00通常是致命的。