Using CSharpCodeProvider to allow user created functions

偶尔善良 提交于 2019-12-02 11:04:39

问题


I have an existing asp.net (c#) application. I need to provide users with a way to create flexibles rules to calculate an effective date given a hiredate and an enrollmentdate.

Some examples of rules that might be used:

  1. The later of hiredate or enrollmentdate
  2. HireDate + 90 Days
  3. The first of the Month after the enrollment date
  4. If the enrollment date is before the 15 of the month, then the effective date is the 1st of the next month. If it is on the 15 or after, it's the 1st of the month after that.

I started out with a handful of offset fields (day offset, month offset, etc...), but as I come across new requirements, I'm coming to realize the current approach isn't flexible enough.

What I would like to do is allow the end user to define a function that returns a date given two parameters (hiredate, enrollmentdate), and store that function in the database. When I need to calculate the effectivedate I'd pull this function out of the database execute it passing in the parameters to get my effectivedate.

My intial reaction was to look for a DSL that would allow me to define date manipulation functions and integrate that into my solution. However my search for an appropriate DSL has turned up nothing.

Now I am wondering whether CSharpCodeProvider might work as a component to the solution. If I pull a string out of a database, and compile it via CsharpCodeProvider, can I enforce that the resulting code matches a function signature (takes 2 datetime parameters, and returns a datatime)?

Is there a way to ensure that the function doesn't have any side effects? For example, No I/O. No reading or session, cache, or application.


回答1:


See my recent answer here: Parsing "DateTime.Now"?

Essentially, you can easily leverage an existing library like FLEE to parse expressions and emit IL for these rules. If you take a look at the examples, you can see how to set up variables for the user expressions to leverage. For example, you may define a "rule" that consists of some input variables (like HireDate or EnrollmentDate), and a user expression/predicate that returns the date. If you expose the DateTime members like I have in the linked answer, then users can leverage those as well.

Just as a quick example, not tested but should give you an idea.

You can setup some custom functions to help, like getting the first day of a month:

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

A basic FLEE setup (you'll have to customize/tweak as necessary)

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();

Then your rules might look like:

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)))"; 



回答2:


The following link has what you're after. Essentially it is a plugable DSL that allows infinite date schedules and sets to be define and then passed to functions, intersected, unioned, etc..

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



来源:https://stackoverflow.com/questions/14730219/using-csharpcodeprovider-to-allow-user-created-functions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!