关于模板中的动态取值 ---反射与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(@"\<C\w*\|\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();
        }

  

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

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

时间: 2024-10-14 12:04:54

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

JS JOSN 静态和动态取值

昨天做前端提示语国际化时候,发现忘记怎么动态取JSON 中的值了.再次记录一下. <script type="text/javascript"> <!-- json = { 'a' : {'b':'c'} } alert(json.a.b)// 静态取值 var a = "a"; var b = "b" alert(json[a][b])//动态取值 //--> </script>

用DataReader在comboBox中显示name,取值id:

定义ItemObject类 classItemObject { public int id; public string name; publicItemObject(int id,string name) { this.id=id; this.name =name; } public override string ToString() { return name; } } 1.实例化对象,加载数据 ItemObject[] io = new ItemObject[3];          

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

原文:C#中float的取值范围和精度 float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double. 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: float x = 3.5F; 如果在以上声明中不使用后缀,则会因为您尝试将一个 double值存储到 float 变量中而发生编译错误. float的取值范围 float占用4个字节,和int是一样,也就是32bit. 1bit(符号位) 8bits(指数位) 23bits(尾数位) 存储方式如下图: 取

C#中float的取值范围和精度分析

本文实例分析了C#中float的取值范围和精度.分享给大家供大家参考.具体分析如下: float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double. 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: float x = 3.5F; 如果在以上声明中不使用后缀,则会因为您尝试将一个 double值存储到 float 变量中而发生编译错误. float的取值范围 float占用4个字节,和int是一样,也就是32bit. 1bit(符号位) 8bits(指数位)

Hibernate中Cascade的取值

Cascade属性的取值有: 1.none:忽略其他关联的对象,默认值,无需设定. 2.save-update:当session通过save(),update(),saveOrUpdate()方法来保存或更新对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象. 3.persist:当session通过persist()方法来保存当前对象时,会级联保存所有关联的新建的临时对象. 4.merge:通过Session的merge()方法来保存当前对象时,会级联融合所有关联的游离对

ul&gt;li中自定义属性后取值的问题

动态赋值的li: $.ajax({ type: "POST", url: "${base}/before/subDemand/listType", success: function(data){ for(var i=0;i<data.listType.length;i++){ $("#show_type").append("<li text='"+data.listType[i].dict_key+"'

mysql中数据类型的取值范围

mysql整型bigint.int.mediumint.smallint 和 tinyint的语法介绍,如下: 1.bigint 从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字),无符号的范围是0到 18446744073709551615.一位为 8 个字节. 2.int 一个正常大小整数.有符号的范围是-2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,64

ul 中的li取值问题

ul 中的li定义的value会自动转换为int.数值,ie 浏览器下大于int最大值,显示int最大值,其他浏览器显示为0. 而且无论你定义什么值,都会转int.默认为1,例如value=中文. 所以如果你想要实现正确取值,就需要换一个li属性例如自定义属性time.或者改一种实现标签元素,例如div.都可以. 也可以在li中定义一个隐藏的input,然后取值:

小程序中map的取值和赋值

1.初始化 resultMap: { "near": [], "join": [], "publish": [] } 2.js中直接取 const val = this.data.apiMap[key]; 3.页面取值 wx:for="{{resultMap.near}}" 4.赋值 let key = "resultMap." + keyName; this.setData({[key]: newList