• .net 动态编译解决考勤计算问题


           由于公司实施SAP HR项目,但是SAP HR对考勤功能真的太弱化了,直接从考勤机上读取的原始打卡记录不能直接传输到HR系统里面,因为SAP HR不能识别那些多余的打卡记录,而且必须把打卡记录进行成组标记(P10,P20),以上标红色的是SAP HR顾问给我的反馈信息。

           这样以来,必须开发一套算法来把多余的打卡记录进行过滤掉,然后标记上是P10还是P20,这样以来,HR系统在做时间评估时才不会出现异常情况。

           需求已经明确,那么就是设计开发的问题,要开发该功能,需要用到的资源:

          1、考勤的排班数据

          2、原始打卡数据

          3、取原始打卡数据的算法

          然后就是确定该功能在我们的外围基础数据平台开发(外围系统是用.net开发的)

         

          由于我们公司的考勤计算方式可能会经常有变化,因为不能把打卡数据的算法写死到代码里面,这样有两种解决方案:1是用侟储过程  2是用动态编译

    考虑到以后数据库的迁移问题,最终采取.net动态编译方式来处理该问题

          具体的实现思想如下:

          1、把算法代码存储在数据库表中

          2、新建一个计算考勤的静态类,类里面定义一个计算考勤的静态方法,传入参数为两上Table类型,一个为排班表,一个为原始打卡记录表,返回参数也

              为DataTable内型,为计算完成后的结果数据,把该段代码保存在一个静态变量里面。

          3、调用计算方法时,把静态类的代码加上代算法代码编译成动态类。

          4、利用反射技术,调用计算方法,返回结果。

          关键性代码如下:

     

    动态编译类:

    DynCompiler.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.CodeDom.Compiler;
    using Microsoft.CSharp;
    using System.Reflection;
    using System.Data;
    
    namespace EDICLibrary
    {
        public class DynCompiler:IDisposable
        {
    
            CodeDomProvider _codeprovide;
            CompilerParameters _parameters; 
            CompilerResults _result = null;
            MethodInfo _method = null;
            Object _instance = null;
           
           
            public DynCompiler()
            {
                _codeprovide = new CSharpCodeProvider();
                _parameters = new CompilerParameters();
                _parameters.GenerateExecutable = false;
                _parameters.GenerateInMemory = true;
                _parameters.ReferencedAssemblies.Add("System.dll");
                _parameters.ReferencedAssemblies.Add("System.Data.dll");
                _parameters.ReferencedAssemblies.Add("System.Xml.dll");
            }
    
            public bool SourceCompiler(string source, out string outputMsg)
            {
                 outputMsg = "";
                 StringBuilder sbout = new StringBuilder();
                 StringBuilder sb = new StringBuilder();
                if (string.IsNullOrEmpty(source))
                {
                    outputMsg = "源代码不能为空!";
                    return false;
                }
                else
                {
                   
                    sb.AppendLine("using System;");
                    sb.AppendLine("using System.Collections.Generic;");
                    sb.AppendLine("using System.Text;");
                    sb.AppendLine("using System.Data;");
                    sb.AppendLine ("using System.Xml;");
                    sb.AppendLine("namespace JMCompiler");
                    sb.AppendLine("{");
                    sb.AppendLine("public class DynCompilerHelper");
                    sb.AppendLine("{");
                    sb.AppendLine("public DataTable Calculate(DataTable dtShiftInfo,DataTable dtTimes)");
                    sb.AppendLine("{");
                    sb.Append(source);
                    sb.Append("}");
                    sb.AppendLine("}");
                    sb.AppendLine("}");
                }
                _result  =  _codeprovide.CompileAssemblyFromSource(_parameters, sb.ToString());
                if (_result.Errors.HasErrors)
                {
                    foreach (string str in _result.Output)
                    {
                        sbout.AppendLine(str);
                    }
                    outputMsg = sbout.ToString();
                    return false;
                }
                else
                {
                    Type _type = _result.CompiledAssembly.GetType("JMCompiler.DynCompilerHelper");
                    _instance = Activator.CreateInstance(_type);
                    _method = _type.GetMethod("Calculate",new Type[]{typeof(DataTable),typeof (DataTable)});
                    outputMsg = "编译成功";
                    return true;
                }
    
            }
    
            public object GetReturnResult(List<DataTable> parameters)
            {             
    
                if (_method == null)
                {
                      throw new Exception ("未进行代码编译");
                }
                return _method.Invoke(_instance, parameters.ToArray());   
            }
    
            
            #region IDisposable 成员
    
            public void Dispose()
            {
                 _codeprovide = null;
                 _parameters = null;
                 _result = null;
                 _method = null;
                 _instance = null;
            }
    
            #endregion
        }
    }
    

    计算考勤类:

    AttdCalculate.cs

     public  class AttdCalculate
        {
            /// <summary>
            /// 计算考勤
            /// </summary>
            /// <param name="source">计算考勤算法代码</param>
            /// <param name="dtShiftInfo">排班信息</param>
            /// <param name="dtTimes">原始打卡的数据</param>
            /// <param name="msg">输出信息</param>
            /// <returns>计算后的结果表</returns>
            public static DataTable Calculate(string source, DataTable dtShiftInfo, DataTable dtTimes, out string msg)
            {
                if (string.IsNullOrEmpty(source))
                {
                    msg = "考勤计算逻辑不能为空";
                    return new DataTable();
                }
                DynCompiler complier = new DynCompiler();
                string output;
                bool result = complier.SourceCompiler(source, out output);
                List<DataTable> lstData = new List<DataTable>();
                lstData.Add(dtShiftInfo);
                lstData.Add(dtTimes);
                if (result)
                {
                    msg = "计算成功";
                    return (DataTable)complier.GetReturnResult(lstData);
                }
                else
                {
    
                    msg = output;
                    return new DataTable();
                }
            }           
            
        }

    考勤调用代码

      //计算公式
                    string Source = string.Empty;
                    //获取计算工式
                    Source  = <获取计算工式的方法>                 
                    string msg;
                    //获取考勤数据
                    
                    DataTable dtResult = MIS.Util.AttdCalculate.Calculate(Source, dtShiftInfo, dtTimes, out msg);

    在写这篇文章的时候,开发的功能还没有投入到正式运行,但是经过最近一段时候的测试来看,没有任何问题。

  • 相关阅读:
    寒假短期学习计划
    PAT 1001 A+B 解题报告
    JavaScript 原型链、继承
    JavaScript 数据扁平化处理
    每周一篇React: 高阶 hoc_component 使用
    每天一道算法题: day1 翻转图像
    项目中下载加权,你是怎么做的,欢迎评论。
    前端封装验证码方法,封装验证码类
    文件下载之后默认不打开实现方式
    文件下载之后默认不打开实现方式
  • 原文地址:https://www.cnblogs.com/miarchen/p/3235011.html
Copyright © 2020-2023  润新知