2012-09-27 10:33:00 weixin_30322405 阅读数 36

 

  前段时间有个项目,因为其中需要使用脚本做模板数据的计算,因此让我对脚本引擎产生了兴趣,于是上网到处寻找资料,于是找到了《龙书》、CodeDom。于是又找了半天,找不到开源的脚本引擎源码,脑袋一热,干脆自己写一个,于是就有了这个用纯c#(非CodeDom)编写的脚本引擎。编写过程中收获良多,目前还不是很完善,效率也不高,仅供学习用,后面会上传源代码。

  下面说明一下:语法参考Javascript,基本的javascript语法都已实现,但是有些内建对象没实现,例如 Date,数据类型支持 数值,字符串(考虑到在代码中执行代码,所以字符串的定义用 '字符串' 而非 "字符串"),对象,布尔值,数组。语法方面基本参考Javascript就行了。在编写这个东西的时候顺带学习了下CodeDom(感叹枉费我弄C#也4年多了,现在才知道这东西,看来水还是太深了),在考虑语法分析的时候就参考了CodeDom的对象结构,如下:

  命名空间定义:

    ScriptEngin.Code :词法分析器

    ScriptEngin.CodeDom:编译后的解释模型,就是上图的结构(都说了是参考CodeDom)

    ScriptEngin.Exceptions:自定义的异常类

      ScriptEngin.Parser:语法分析器

    ScriptEngin.RunTime:运行时解释执行器

    ScriptEngin.RunTimeType:处理c#对象和脚本对象的映射(还未完善)

    下面贴一段调用代码:

    

 1 string code1 = @"
 2 
 3 var str='字符串申明';
 4 var obj={name:'对象申明',num:100,fun:function(a,b){return a+b;}};
 5 var arr=['这个是数组','123'];
 6 var arr2=[['多维数组','111'],['222','223']];
 7 
 8 function testClass()
 9 {
10     this.name='成员属性';
11     this.MemFun=function(){
12         return '成员函数';
13     }
14 }
15 var newObj=new testClass();
16 var nameMem=newObj.name;
17 
18 
19 function testFun(a,v)
20 {
21    count=0;
22    for(i=0;i<v;i++)
23    {
24        count+=a;
25    }
26    return count;
27 }
28 
29 
30 ";
31             Script scr = new Script();
32             //设置传入脚本的参数,这里传入的参数在脚本中可做变量用
33             scr.Paramers.Set("testbool", true);
34             scr.Paramers.Set("testString", "abc");
35 
36             //编译并运行全局代码
37             scr.Run(code1);
38 
39             //获取运行时变量,PS:暂时只能返回数值、字符串、Boolean值
40             object varValue = scr.Paramers.Get("str");
41 
42             //调用指定函数,能返回的数据同上
43             object value= scr.Call("testFun",300,200);

 

   目前未做大量测试,可能会存在些许Bug,如果大家发现了请告诉我,谢谢。

  (第一次写博,大家见笑了)

   源码在此

 


  呵呵,感谢大家的支持!

  关于有人问这个东西在实际项目中的用处这个问题,这个嘛其实还是很多的,例如在项目中有些地方是需要用户自定义的,比如报表模板,界面模板等等。当用户需要做一些简单计算的时候,脚本引擎的作用就可以体现出来了。总不可能当用户需要在模板中做计算的时候,你来给他修改代码然后重新发布吧(这里我说的不是很清楚)。另外,作为一个程序员,多了解一些编译原理的东西总没坏处的。

  呵呵,如果对脚本引擎和编译原理感兴趣的人多的话,我也许会写一系列的博文,用最浅显的语言给你解释原理,用较简单的方法让你知道如何写一个脚本引擎。其实看了《龙书》快4个多月的时间了,其中的很多东西也还不是很明白,最快乐的就是某天的某个时刻忽然领悟其中某部分知识的时候,那种好心情能让自己高兴一整天,恨不得马上坐下写出代码来验证自己的想法。

  希望和大家一起学习,一起研究,我们是程序员,是计算机的灵魂工程师~~~呵呵

转载于:https://www.cnblogs.com/TianY/archive/2012/09/27/2704267.html

2014-09-01 09:07:00 dongfushu7972 阅读数 38
public static object Create(string path)
{
    var provOptions = new Dictionary<string, string>();
    provOptions.Add("CompilerVersion", "v3.5");

    CodeDomProvider codeDomProvider = new CSharpCodeProvider(provOptions);
    CompilerParameters compilerParameters = new CompilerParameters();
    compilerParameters.GenerateExecutable = false;
    compilerParameters.GenerateInMemory = true;
    compilerParameters.ReferencedAssemblies.Add("mscorlib.dll");
    compilerParameters.ReferencedAssemblies.Add("System.dll");
    compilerParameters.ReferencedAssemblies.Add("System.Core.dll");
    string[] code = new string[1];
    code[0] = File.ReadAllText(path);
    CompilerResults compilerResults =
    codeDomProvider.CompileAssemblyFromSource(compilerParameters, code);

    Assembly ass = compilerResults.CompiledAssembly;
    var obj = ass.GetTypes().FirstOrDefault();
    return Activator.CreateInstance(obj);
}

一定要引用mscorlib,否则CodeDom编译出错

转载于:https://www.cnblogs.com/hont/p/3948553.html

2019-11-21 13:23:28 birdfly2015 阅读数 53

一、背景

小伙伴们在用CodeDom生成类属性时,如果想属性只表示为以下部分

public string MyProperty { get; set; }

如何实现呢?

二、思路

使用如下代码即可

     var field = new CodeMemberField
            {
                Attributes = MemberAttributes.Public | MemberAttributes.Final,
                Name = "MyProperty",
                Type = new CodeTypeReference(typeof(string)),
            };
            field.Name += " { get; set; }";

但是这样生成的代码会出现如下瑕疵
在这句代码后面会多一个 ;

public string MyProperty { get; set; };

为了解决这个问题,在上面的代码中

//将这部分
  field.Name += " { get; set; }";
  改为
  field.Name += " { get; set; }//";

最后代码就会变成这样子

public string MyProperty { get; set; }//;

三、注意事项

1.关于如何使用CodeDom自动生成代码,可以参看博主的这篇文章C#之自动生成类的方法探究
2.我是黑夜の骑士,欢迎大家关注我的博客,笔者将持续输出BIM相关软件开发以及编程干货;
3.欢迎加入BIM行业开发交流1群,获取更多开发资料 群号:711844216

2012-05-24 09:56:00 weixin_30389003 阅读数 21

很早就研究过CodeDom,当时觉得挺有意思的,但是一时也想不到具体应用在哪,于是写了个DEMO就放在那里了。

昨天项目里有个地方要把一大堆值拿来计算公式,每一个值还都是需要单独计算求和,并且最后的公式还不一定,最后还需要输出所有的值,搞的我有点头大,其实也不算太麻烦,但是手工定义一大堆变量再去操作我怎么想怎么不爽,突然想起CodeDom,于是尝试了下, 果然爽多了。

首先构造类,将所有要计算的值都构造成变量,把变量的赋值加减和公式的计算都放在类的一个方法里,构造完类之后调用一下方法,该计算的就都计算完了,最后用反射输出所有值就OK了。

虽然是个简单的应用,不过还是很有感觉,嘿嘿,不写重复的东西就是爽。

private string GetSumScript(Dictionary<string, DeviceInfo> dictAllDevs)
    {
        StringBuilder classSrc = new StringBuilder();
        classSrc.Append(" using  System;" + Environment.NewLine);
        classSrc.Append(" namespace  A { " + Environment.NewLine);
        classSrc.Append("public  class  TempSum{ " + Environment.NewLine);//创建temp类
        List<string> propList = new List<string>();
        string strSum = "public void Run(){";//temp类中的计算方法
        foreach (KeyValuePair<string, DeviceInfo> item in dictAllDevs)
        {
            SumValues(ref classSrc, ref strSum, ref propList, item, 4);
            SumValues(ref classSrc, ref strSum, ref propList, item, 10);
            SumValues(ref classSrc, ref strSum, ref propList, item, 20);
        }
        strSum += "}";
        classSrc.Append(strSum + Environment.NewLine);
        classSrc.Append("}" + Environment.NewLine);
        classSrc.Append("}" + Environment.NewLine);
        object obj = BulidClass(classSrc);//创建类,调用计算方法
        return GetObjFillScript(obj);//输出计算结果
    }
    private void SumValues(ref StringBuilder classSrc, ref string strSum, ref  List<string> propList, KeyValuePair<string, DeviceInfo> item, int valueIndex)
    {
        double value = 0;
        string strProp = "SUMVALUE" + item.Value.Level.ToString() + item.Value.Tagindex + valueIndex.ToString();//类中的变量名
        switch (valueIndex)
        {
            case 4:
                value = item.Value.LoadValue4;
                break;
            case 10:
                value = item.Value.LoadValue10;
                break;
            default:
                value = item.Value.LoadValue20;
                break;
        }
        if (!propList.Contains(strProp))
        {
            classSrc.Append("public double " + strProp + "=" + value + ";" + Environment.NewLine);//如果不存在就声明它
            propList.Add(strProp);
        }
        else
        {
            strSum += GetFormula(strProp, value, item);//存在则使用公式计算
        }
    }
    private object BulidClass(StringBuilder classSrc)
    {
        string source = classSrc.ToString();
        CSharpCodeProvider compiler = new CSharpCodeProvider();
        CompilerParameters paras = new CompilerParameters();
        paras.GenerateExecutable = false;
        paras.GenerateInMemory = true;
        CompilerResults result = compiler.CompileAssemblyFromSource(paras, source);
        Assembly assembly = result.CompiledAssembly;
        object eval = assembly.CreateInstance("A.TempSum");
        MethodInfo method = eval.GetType().GetMethod("Run");//调用计算方法
        object reobj = method.Invoke(eval, null);
        return eval;
    }
    private string GetObjFillScript(object obj)
    {
        string str = "";
        Type type = obj.GetType();
        foreach (FieldInfo fi in type.GetFields())//用反射输出所有值
        {
            str += "content.add('" + fi.Name.ToUpper() + "','" + fi.GetValue(obj) + "',null);";
        }
        return str;
    }

转载于:https://www.cnblogs.com/nightzsze/archive/2012/05/24/2516080.html

没有更多推荐了,返回首页