2013-02-06 28 views
1

我有一个现有的asp.net(c#)应用程序。我需要为用户提供一种创建弹性规则的方法,以计算给定入职日期和注册日期的生效日期。使用CSharpCodeProvider允许用户创建功能

可能被使用的规则的一些例子:

  1. HIREDATE的后期或enrollmentdate
  2. 雇佣日期+ 90天
  3. 报名日期后的第一个月
  4. 如果注册日期在本月15日之前,那么生效日期是下个月的第一天。如果是在15岁或之后,则是此后一个月的第一天。

我开始时使用了一些偏移字段(日偏移,月偏移等),但是当我遇到新的需求时,我意识到当前的方法不够灵活。

我想要做的是允许最终用户定义一个函数,该函数返回给定两个参数(hiredate,enrollmentdate)的日期,并将该函数存储在数据库中。当我需要计算有效日期时,我会从数据库中取出这个函数,执行它传递参数来获得我的有效日期。

我的最初反应是寻找一个DSL,它可以让我定义日期操作函数并将其集成到我的解决方案中。然而,我寻找合适的DSL没有任何结果。

现在我想知道CSharpCodeProvider是否可以作为解决方案的组件工作。 如果我从数据库中提取出一个字符串,并通过CsharpCodeProvider进行编译,我可以强制生成的代码与函数签名相匹配(需要2个日期时间参数,并返回一个数据时间)?

有没有办法确保函数没有任何副作用?例如,没有I/O。没有阅读或会话,缓存或应用程序。

回答

2

见我这里最近的答案:Parsing "DateTime.Now"?

本质上讲,你可以很容易地利用诸如FLEE现有的库来解析表达式,并发出IL这些规则。如果你看看这些例子,你可以看到如何设置用户表达式的变量来利用。例如,您可以定义一个由某些输入变量(如HireDateEnrollmentDate)组成的“规则”以及返回日期的用户表达式/谓词。如果您在链接的答案中公开DateTime成员,那么用户也可以利用这些成员。

就像一个简单的例子,没有经过测试,但应该给你一个想法。

您可以设置一些自定义的功能,帮助,就像得到了一个月的第一天:

public static class CustomFunctions 
{ 
    public static DateTime GetFirstDayOfMonth(DateTime date) 
    { 
     return new DateTime(date.Year, date.Month, 1); 
    } 
} 

基本FLEE设置(你必须定制/调整必要)

ExpressionContext context = new ExpressionContext(); 

//Tell FLEE to expect a DateTime result; if the expression evaluates otherwise, 
//throws an ExpressionCompileException when compiling the expression 
context.Options.ResultType = typeof(DateTime); 

//Instruct FLEE to expose the `DateTime` static members and have 
//them accessible via "DateTime". 
//This mimics the same exact C# syntax to access `DateTime.Now` 
context.Imports.AddType(typeof(DateTime), "DateTime"); 
context.Imports.AddType(typeof(CustomFunctions)); 

//Expose your key variables like HireDate and EnrollmentDate 
context.Variables["HireDate"] = GetHireDate(); //DateTime I suppose 
context.Variables["EnrollmentDate"] = GetEnrollmentDate(); //DateTime I suppose 

//Parse the expression, naturally the string would come from your data source 
IGenericExpression<DateTime> expression = context.CompileGeneric<DateTime>(GetYourRule(), context); 

DateTime date = expression.Evaluate(); 

那么你的规则可能看起来像:

string rule1 = "if(HireDate > EnrollmentDate, HireDate, EnrollmentDate)"; 
string rule2 = "HireDate.AddDays(90)"; 
string rule3 = "GetFirstDayOfMonth(EnrollmentDate.AddMonths(1))"; 
string rule4 = "GetFirstDayOfMonth(EnrollmentDate.AddMonths(if(EnrollmentDate.Day < 15, 1, 2)))"; 
+0

可以FLEE可空类型的工作?让我们说,而不是构建一个需要两个DateTime参数的表达式,如果雇用日期未知,我需要能够将null传递给HireDate? – Aheho

+0

@Aheho我_think_所以,但你最好避免使用它的各种隐式运算符并使用它的'.Value'属性。例如,如果'HireDate'是键入'DateTime?',而不是简单地检查'if(HireDate> DateTime.Now)'你可能想'if(HireDate.Value> DateTime.Now)''。你也可以避免可空可以有一个单独的布尔标志暴露“HasHireDate”,如果这是'false',那么'HireDate'可能是过去的默认值或只是'new DateTime()' –

0

下面的链接有你以后。本质上,它是可插式DSL,允许无限的日期时间表和设置要定义它们,然后传递给函数,交叉,联合在一起,等等。

http://code.google.com/p/drules/

相关问题