Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用CSharpCodeProvider允许用户创建函数_C#_.net_Runtime - Fatal编程技术网

C# 使用CSharpCodeProvider允许用户创建函数

C# 使用CSharpCodeProvider允许用户创建函数,c#,.net,runtime,C#,.net,Runtime,我有一个现有的asp.net(c#)应用程序。我需要为用户提供一种创建灵活规则的方法,以计算给定雇佣日期和注册日期的生效日期 可能使用的一些规则示例: 雇佣日期或注册日期中的较晚者 雇佣+90天 注册日期后的第一个月 如果报名日期在当月15日之前,则生效日期为下个月1日。如果是在15号或之后,则是该月的第1天 我开始时有一些偏移字段(日偏移、月偏移等),但当我遇到新的需求时,我逐渐意识到当前的方法不够灵活 我想做的是允许最终用户定义一个函数,该函数返回给定两个参数(hiredate、enroll

我有一个现有的asp.net(c#)应用程序。我需要为用户提供一种创建灵活规则的方法,以计算给定雇佣日期和注册日期的生效日期

可能使用的一些规则示例:

  • 雇佣日期或注册日期中的较晚者
  • 雇佣+90天
  • 注册日期后的第一个月
  • 如果报名日期在当月15日之前,则生效日期为下个月1日。如果是在15号或之后,则是该月的第1天
  • 我开始时有一些偏移字段(日偏移、月偏移等),但当我遇到新的需求时,我逐渐意识到当前的方法不够灵活

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

    我最初的反应是寻找一种DSL,它允许我定义日期操作函数并将其集成到我的解决方案中。然而,我寻找合适的DSL却一无所获

    现在我想知道CSharpCodeProvider是否可以作为解决方案的一个组件。 如果我从数据库中提取一个字符串,并通过CsharpCodeProvider编译它,我可以强制执行生成的代码与函数签名匹配(接受2个datetime参数,并返回一个datatime)


    有没有办法确保该功能没有任何副作用?例如,没有I/O。没有读取或会话、缓存或应用程序

    请参见我最近的回答:

    本质上,您可以轻松地利用现有库来解析表达式并为这些规则发出IL。如果您看一下这些示例,就可以看到如何为用户表达式设置要利用的变量。例如,您可以定义由一些输入变量(如
    HireDate
    EnrollmentDate
    )和返回日期的用户表达式/谓词组成的“规则”。如果像我在链接答案中那样公开
    DateTime
    成员,那么用户也可以利用这些成员

    作为一个简单的例子,没有测试,但应该给你一个想法

    您可以设置一些自定义函数以提供帮助,例如获取一个月的第一天:

    public static class CustomFunctions
    {
        public static DateTime GetFirstDayOfMonth(DateTime date)
        {
            return new DateTime(date.Year, date.Month, 1);
        }
    }
    
    基本的逃离设置(您必须根据需要进行自定义/调整)

    ExpressionContext=newexpressioncontext();
    //告诉逃跑者期待一个日期时间结果;如果表达式的计算结果不是这样,
    //编译表达式时引发ExpressionCompileException
    context.Options.ResultType=typeof(DateTime);
    //指示Runge公开'DateTime'静态成员并
    //它们可以通过“日期时间”访问。
    //这与访问“DateTime.Now”的C#语法完全相同`
    AddType(typeof(DateTime),“DateTime”);
    AddType(typeof(CustomFunctions));
    //公开关键变量,如HireDate和EnrollmentDate
    变量[“HireDate”]=GetHireDate()//我想是约会时间吧
    context.Variables[“EnrollmentDate”]=GetEnrollmentDate()//我想是约会时间吧
    //解析表达式时,字符串自然会来自您的数据源
    IGenericExpression expression=context.CompileGeneric(GetYourRule(),context);
    DateTime日期=表达式.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)))"; 
    
    string rule1=“如果(HireDate>EnrollmentDate,HireDate,EnrollmentDate)”;
    字符串规则2=“HireDate.AddDays(90)”;
    字符串规则3=“GetFirstDayOfMonth(EnrollmentDate.AddMonths(1))”;
    string rule4=“GetFirstDayOfMonth(EnrollmentDate.AddMonths)(如果(EnrollmentDate.Day<15,1,2))”;
    
    以下链接说明了您的目的。本质上,它是一种可插入的DSL,允许定义无限的日期计划和集合,然后将其传递给函数、交叉、联合等


    可以使用可为空的类型吗?比方说,如果雇用日期未知,我需要能够将null传递给HireDate,而不是构建一个包含两个DateTime参数的表达式?@Aheho我想是的,但您最好避免使用它的各种隐式运算符,并使用它的
    .Value
    属性。例如,如果
    HireDate
    是type
    DateTime?
    ,而不是简单地检查
    if(HireDate>DateTime.Now)
    您可能需要
    if(HireDate.Value>DateTime.Now)
    。您还可以完全避免空值,使用单独的布尔标志“HasHireDate”,如果这是
    false
    ,则
    HireDate
    可能是过去的默认值,或者只是
    new DateTime()
    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)))";