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

但是现在遇到两种场景:

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

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

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

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

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

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

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

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

  1. /// <summary>
  2. /// CShrapEval 的摘要说明
  3. /// </summary>
  4. public class CShrapEval
  5. {
  6.  
  7. /// <summary>
  8. /// 计算结果,如果表达式出错则抛出异常
  9. /// </summary>
  10. public static object Eval(string action,Type type,object obj,object[] parm)
  11. {
  12. return type.InvokeMember(
  13. action,
  14. BindingFlags.InvokeMethod,
  15. null,
  16. obj,
  17. parm
  18. );
  19. }
  20.  
  21. public static object Eval(string Cstring, Type type, object obj)
  22. {
  23. string action = Cstring.Split('|')[0];
  24. object[] parm = Cstring.Split('|')[1].Split(',');
  25. return type.InvokeMember(
  26. action,
  27. BindingFlags.InvokeMethod,
  28. null,
  29. obj,
  30. parm
  31. );
  32. }
  33. }

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

  1. /**/
  2. /// <summary>
  3. /// 动态求值
  4. /// </summary>
  5. public class JavaEval
  6. {
  7. /**/
  8. /// <summary>
  9. /// 计算结果,如果表达式出错则抛出异常
  10. /// </summary>
  11. /// <param name="statement">表达式,如"1+2+3+4"</param>
  12. /// <returns>结果</returns>
  13. public static object Eval(string statement)
  14. {
  15. return _evaluatorType.InvokeMember(
  16. "Eval",
  17. BindingFlags.InvokeMethod,
  18. null,
  19. _evaluator,
  20. new object[] { statement }
  21. );
  22. }
  23. /**/
  24. /// <summary>
  25. ///
  26. /// </summary>
  27. static JavaEval()
  28. {
  29. //构造JScript的编译驱动代码
  30. CodeDomProvider provider = CodeDomProvider.CreateProvider("JScript");
  31.  
  32. CompilerParameters parameters;
  33. parameters = new CompilerParameters();
  34. parameters.GenerateInMemory = true;
  35.  
  36. CompilerResults results;
  37. results = provider.CompileAssemblyFromSource(parameters, _jscriptSource);
  38.  
  39. Assembly assembly = results.CompiledAssembly;
  40. _evaluatorType = assembly.GetType("Evaluator");
  41.  
  42. _evaluator = Activator.CreateInstance(_evaluatorType);
  43. }
  44.  
  45. private static object _evaluator = null;
  46. private static Type _evaluatorType = null;
  47. /**/
  48. /// <summary>
  49. /// JScript代码
  50. /// </summary>
  51. private static readonly string _jscriptSource =
  52.  
  53. @"class Evaluator
  54. {
  55. public function Eval(expr : String) : String
  56. {
  57. return eval(expr);
  58. }
  59. }";
  60. }

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

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

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

  1. public void ExportDoc()
  2. {
  3. ExportReplace();
  4. foreach (NodeTemplate temp in DocTemplateList)
  5. {
  6. ExportDoc(temp);
  7. }
  8. if (ActionObject != null)
  9. {
  10. //动态取值
  11. ExportDymic();
  12. }
  13. }
  14.  
  15. //定义C表达式
  16. System.Text.RegularExpressions.Regex RegexC = new System.Text.RegularExpressions.Regex(@"\<C\w*\|\w*[\,\w*]*\\\>");
  17. //定义J表达式
  18. System.Text.RegularExpressions.Regex RegexJ = new System.Text.RegularExpressions.Regex(@"\<J^\>*\\\>");
  19.  
  20. //业务逻辑理论为先处理C在处理J,但是C与J由存在循环处理的过程
  21. public void ExportDymic()
  22. {
  23. var MatchesS = RegexC.Matches(doc.GetText());
  24. foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
  25. {
  26. string Cstring = MatchC.Value.Replace("<C", "").Replace("\\>", "");
  27. string result = CEval(Cstring);
  28. //CShrapEval.Eval(Cstring, this.GetType(), this).ToString();
  29. //A = A.Replace(MatchC.Value, result);
  30. doc.Range.Replace(MatchC.Value, result, false, false);
  31. }
  32. MatchesS = RegexJ.Matches(doc.GetText());
  33. foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
  34. {
  35. string Jstring = MatchC.Value.Replace("<J", "").Replace("\\>", "");
  36. string result = JavaEval.Eval(Jstring).ToString();
  37. doc.Range.Replace(MatchC.Value, result, false, false);
  38. }
  39.  
  40. }
  41.  
  42. public string CEval(string A)
  43. {
  44. var MatchesS = RegexC.Matches(A);
  45. foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
  46. {
  47. string Cstring = MatchC.Value.Replace("<C", "").Replace("\\>", "");
  48. string result = CEval(Cstring).ToString();
  49. A = A.Replace(MatchC.Value, result);
  50. }
  51. MatchesS = RegexJ.Matches(A);
  52. foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
  53. {
  54. string Jstring = MatchC.Value.Replace("<J", "").Replace("\\>", "");
  55. string result = JEval(Jstring).ToString();
  56. A = A.Replace(MatchC.Value, result);
  57. }
  58.  
  59. return CShrapEval.Eval(A, ActionObject.GetType(), ActionObject).ToString();
  60. }
  61.  
  62. public string JEval(string A)
  63. {
  64. var MatchesS = RegexC.Matches(A);
  65. foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
  66. {
  67. string Cstring = MatchC.Value.Replace("<C", "").Replace("\\>", "");
  68. string result = CEval(Cstring).ToString();
  69. A = A.Replace(MatchC.Value, result);
  70. }
  71. MatchesS = RegexJ.Matches(A);
  72. foreach (System.Text.RegularExpressions.Match MatchC in MatchesS)
  73. {
  74. string Jstring = MatchC.Value.Replace("<J", "").Replace("\\>", "");
  75. string result = JEval(Jstring).ToString();
  76. A = A.Replace(MatchC.Value, result);
  77. }
  78. return JavaEval.Eval(A).ToString();
  79. }

  

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

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

关于模板中的动态取值 ---反射与javascript脚本编译的更多相关文章

  1. mybatis中两种取值方式?谈谈Spring框架理解?

    1.mybatis中两种取值方式? 回答:Mybatis中取值方式有几种?各自区别是什么? Mybatis取值方式就是说在Mapper文件中获取service传过来的值的方法,总共有两种方式,通过 $ ...

  2. Vue 列动态取值

    在前端开发过程中,可能会遇到列动态取值的情况,即列表中某列的取值由两个或以上的字段的值决定. 用 Vue 实现的话可以用如下代码解决 <template slot-scope="sco ...

  3. C#中float的取值范围和精度

    原文:C#中float的取值范围和精度 float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double. 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: floa ...

  4. JSP中EL表达式取值问题记录(已解决)

    ***************************2015-10-28 22:21************************* 问题描述如下: 在当前的jsp页面已经有了如下代码: < ...

  5. C语言中数据类型的取值范围

    C语言中数据类型的取值范围如下:char -128 ~ +127 (1 Byte)short -32767 ~ + 32768 (2 Bytes)unsigned short 0 ~ 65536 (2 ...

  6. loadrunner 脚本优化-参数化之场景中的参数化取值

    脚本优化-场景中的参数化取值 by:授客 QQ:1033553122   Action() { lr_eval_string("{NewParam}"); lr_eval_stri ...

  7. mysql中数据类型的取值范围

    mysql整型bigint.int.mediumint.smallint 和 tinyint的语法介绍,如下: 1.bigint 从 -2^63 (-9223372036854775808) 到 2^ ...

  8. Struts2中EL表达式取值

    http://blog.csdn.net/cuihaiyang/article/details/41950141 (写的不错,可以知道为什么struts2可以用El取属性值的问题.正常el从reque ...

  9. 基础学习:C#中float的取值范围和精度

    float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double. 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: float x = 3.5F; 如果在以上声明中 ...

随机推荐

  1. 尼玛的,不学ORACLE RAC就不能叫高大上啊

    刚才趁这段时间和机会,进去好好套弄一下. 我看不得会ORACLE人的嘴脸,于是,,,,我想试试~~~

  2. Spring: DispacherServlet和ContextLoaderListener中的WebApplicationContext的关系

    在Web容器(比如Tomcat)中配置Spring时,你可能已经司空见惯于web.xml文件中的以下配置代码: <context-param> <param-name>cont ...

  3. iostat 使用说明

    LINUX [oracle@perass back]$ iostat -m 1 10 Linux 2.6.18-194.el5 (perass) 03/01/2014 avg-cpu: %user % ...

  4. weblogic jsp 不生效解决方法

    1. 检查weblogic.xml配置文件,其中如果有: <jsp-descriptor> <jsp-param> <param-name>pageCheckSec ...

  5. 【转】Android开发中adb启动失败adb连接异常的解决办法 offline

    原文网址:http://www.cnblogs.com/yejiurui/p/4173521.html 一.情况描述: 我们在使用eclipse开发有时候会出现adb连接异常中,有时候控制台会打印出来 ...

  6. 自己做的网页页面导航浏览JS/JQuery_版本2(优化边缘)

    版本2增加了宽宽的边界,边界内鼠标也可以导航.边界对应这HTML页面的边界.目前右下角有时会导致功能失效.版本1. 这次找了个更好的例子,实践中产生这个需求的真实例子,点我Demo. 需求: 版本1: ...

  7. java JDK安装

    JDK安装包下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 图释安装 ...

  8. Selenium webdriver firefox 路径设置问题

    问题: Cannot find firefox binary in PATH. Make sure firefox is installed. 原因:selenium找不到Firefox浏览器. 方法 ...

  9. Rules

    我们之前处理异常的时候用到过Rules,当然还有很多其他规则.Rules允许弹性的添加或者重定义测试方法的行为.测试者可以重复使用或者扩展下面的某一个Rules,也可以写一个属于自己的规则. 这里先展 ...

  10. hdoj 1728 逃离迷宫

    逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...