• 关于模板中的动态取值 ---反射与javascript脚本编译


          在项目中经常遇到一个问题,打印word或者打印excel的时候,我们经常使用一对一的赋值或者批量替换的方式来对模板进行修改。

          但是现在遇到两种场景:

          1、取值是通过自定以方法进行取值的。

           如:一个销售单据,会涉及到很多种费用,并且这些费用是由后台配置的,非常灵活。但是我们在制作打印模板时取值各项费用我们该如何去定义他呢,如何给他赋值呢?我们如果针对这一个场景下的模板进行一个特殊定义后,在打印另一份单据或者遇到同样的取值非常灵活的数据,是不是也需要进行特殊处理呢。

          2、取值是通过自行定义进行取值的。

          如:还是一个销售单据,我们打印的可能是销售价格,成本、毛利,但是如果我们打印的时候涉及到提成配比,提成配比可能是根据销售价格算的,可能根据毛利算的,可能根据效益来算的,那么是不是我们在做这个模板的时候定义:提成(按成本)、提成(按毛利)、提成...。  

         在这中情况下,我的解决方案是采用反射与javascript进行处理:

         这里大致讲述一下我的解决思路,各位过路大神,各位奋战一线的程序猿们,看过笑过,不喜勿喷~

         第一步:建立两种Eval方法,来解析表达式

       C#Eval反射式:(此种方式主要应对在程序中自定义的方法,根据参数及方法来模拟程序中的计算,并将结果返回过去,这种方法必须制定处理他的主体Object)

                 

    /// <summary>
    /// CShrapEval 的摘要说明
    /// </summary>
    public class CShrapEval
    {
    	 
    	 
        /// <summary>
        /// 计算结果,如果表达式出错则抛出异常
        /// </summary> 
        public static object Eval(string action,Type type,object obj,object[] parm)
        {
            return type.InvokeMember(
                        action,
                        BindingFlags.InvokeMethod,
                        null,
                        obj,
                      parm 
                     );
        }
    
    
        public static object Eval(string Cstring, Type type, object obj)
        {
            string action = Cstring.Split('|')[0];
            object[] parm = Cstring.Split('|')[1].Split(',');
            return type.InvokeMember(
                        action,
                        BindingFlags.InvokeMethod,
                        null,
                        obj,
                      parm
                     );
        }
    }
    

      JavaScript脚本编译方式:模拟javascript工作方式去处理一个表示式,可以使用一个javascript常用函数(如getdate()  length等),灵活方便

    /**/
    /// <summary>
    /// 动态求值
    /// </summary>
    public class JavaEval
    {
        /**/
        /// <summary>
        /// 计算结果,如果表达式出错则抛出异常
        /// </summary>
        /// <param name="statement">表达式,如"1+2+3+4"</param>
        /// <returns>结果</returns>
        public static object Eval(string statement)
        {
            return _evaluatorType.InvokeMember(
                        "Eval",
                        BindingFlags.InvokeMethod,
                        null,
                        _evaluator,
                        new object[] { statement }
                     );
        }
        /**/
        /// <summary>
        /// 
        /// </summary>
        static JavaEval()
        {
            //构造JScript的编译驱动代码
            CodeDomProvider provider = CodeDomProvider.CreateProvider("JScript");
    
            CompilerParameters parameters;
            parameters = new CompilerParameters();
            parameters.GenerateInMemory = true;
    
            CompilerResults results;
            results = provider.CompileAssemblyFromSource(parameters, _jscriptSource);
    
            Assembly assembly = results.CompiledAssembly;
            _evaluatorType = assembly.GetType("Evaluator");
    
            _evaluator = Activator.CreateInstance(_evaluatorType);
        }
    
        private static object _evaluator = null;
        private static Type _evaluatorType = null;
        /**/
        /// <summary>
        /// JScript代码
        /// </summary>
        private static readonly string _jscriptSource =
    
            @"class Evaluator
                  {
                      public function Eval(expr : String) : String 
                      { 
                         return eval(expr); 
                      }
                  }";
    }
    

      第二步、构建好两个eval之后我们就需要在程序中去识别那些是C#,那些是javascript代码断

          这里我处理的办法是:<c ...代码  /> 和<J ...代码 />使用这两种方式分别标示是那种代码

          然后在处理中我们只需要找出那些是C代码 那些是J代码,并且对代码断进行计算

        

           public void ExportDoc()
            {
                ExportReplace();
                foreach (NodeTemplate temp in DocTemplateList)
                {
                    ExportDoc(temp);
                }
                if (ActionObject != null)
                {
                    //动态取值
                    ExportDymic();
                }
            }
    
            //定义C表达式
            System.Text.RegularExpressions.Regex RegexC = new System.Text.RegularExpressions.Regex(@"<Cw*|w*[\,w*]*\>");
            //定义J表达式
            System.Text.RegularExpressions.Regex RegexJ = new System.Text.RegularExpressions.Regex(@"<J^>*\>");
    
            //业务逻辑理论为先处理C在处理J,但是C与J由存在循环处理的过程
            public void ExportDymic()
            {
                var MatchesS = RegexC.Matches(doc.GetText());
                foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
                {
                    string Cstring = MatchC.Value.Replace("<C", "").Replace("\>", "");
                    string result = CEval(Cstring);
                    //CShrapEval.Eval(Cstring, this.GetType(), this).ToString();
                    //A = A.Replace(MatchC.Value, result);
                    doc.Range.Replace(MatchC.Value, result, false, false);
                }
                MatchesS = RegexJ.Matches(doc.GetText());
                foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
                {
                    string Jstring = MatchC.Value.Replace("<J", "").Replace("\>", "");
                    string result = JavaEval.Eval(Jstring).ToString();
                    doc.Range.Replace(MatchC.Value, result, false, false);
                }
            
            }
    
            public string CEval(string A)
            {
                var MatchesS = RegexC.Matches(A);
                foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
                {
                    string Cstring = MatchC.Value.Replace("<C", "").Replace("\>", "");
                    string result =  CEval(Cstring).ToString();
                    A = A.Replace(MatchC.Value, result);
                }
                MatchesS = RegexJ.Matches(A);
                foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
                {
                    string Jstring = MatchC.Value.Replace("<J", "").Replace("\>", "");
                    string result = JEval(Jstring).ToString();
                    A = A.Replace(MatchC.Value, result);
                }
              
               return CShrapEval.Eval(A, ActionObject.GetType(), ActionObject).ToString();
            }
    
            public string JEval(string A)
            {
                var MatchesS = RegexC.Matches(A);
                foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
                {
                    string Cstring = MatchC.Value.Replace("<C", "").Replace("\>", "");
                    string result = CEval(Cstring).ToString();
                    A = A.Replace(MatchC.Value, result);
                }
                 MatchesS = RegexJ.Matches(A);
                foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
                {
                    string Jstring = MatchC.Value.Replace("<J", "").Replace("\>", "");
                    string result = JEval(Jstring).ToString();
                    A = A.Replace(MatchC.Value, result);
                }
                return JavaEval.Eval(A).ToString();
            }
    

      

    这样就可以对表达进行精确的解析了,当然目前还有一些未考虑完全的地方 ,待各位看客老爷指点。

    好的~今天就贴到这里, 后期看看被喷的程度来确定是否继续在博客园发一些日志

      

        

  • 相关阅读:
    垃圾回收于内存优化(摘自网络)
    as3.0 动态改变影片剪辑的颜色
    2进制_8进制_16进制之间快速转换的技巧.txt
    24位真彩色转换为8位灰度图片(完整代码)
    大端模式和小端模式
    如何将真彩色图转换为各种灰度图
    C++图像缩放
    二进制转十进制快速转换方法
    电脑上运行的使用大全
    移位运算符详解
  • 原文地址:https://www.cnblogs.com/webda/p/4543609.html
Copyright © 2020-2023  润新知