zoukankan      html  css  js  c++  java
  • C# 动态类型与动态编译简介

    关于C#的动态类型与动态编译的简介,主要是一个Demo。

    动态类型

    动态类型的应用场景

    1. 可以减少强制转换(强制转换其实挺好的,让程序猿清楚地指定自己做了什么,不至于出错时不知所措)
    2. 简化反射的写法。
    3. 与动态语言交互。
    // Install-Package IronPython // 需要安装此 Nuget包
    // 引入动态类型之后
    // 可以在C#语言中与动态语言进行交互
    // 下面演示在C#中使用动态语言Python
    
    ScriptEngine engine = Python.CreateEngine();
    
    // 调用Python语言的print函数来输出
    engine.Execute("print 'Hello world'");
    
    // 调用python求解汉罗塔问题
    engine.Execute(PythonCode1());
    
    // 调用python进行计算,返回 dynamic 类型
    dynamic result = engine.Execute("123+456");
    
    public static string PythonCode1()
    {
        string code = "count=0
    " +
                        "def move(n,A,B,C):
    " +
                        "    global count
    " +
                        "    if(n==1):
    " +
                        "        print(A+"->"+C)
    " +
                        "        count = count + 1
    " +
                        "        return
    " +
                        "    move(n - 1, A, C, B)
    " +
                        "    move(1, A, B, C)
    " +
                        "    move(n - 1, B, A, C)
    " +
                        "    return
    " +
                        "move(5,"A","B","C")";
        return code;
    }
    
    

    动态编译

    javascript 和 matlab 等脚本语言会有 eval 这个函数,可以将一些动态生成的字符串作为代码执行,某些情况下很实用。
    C#同样支持动态编译。

    最主要的两个类:
    CodeDomProviderCompilerParameters
    前者相当于编译器,后者相当于编译器参数。

    public static void Test1()
    {
        CodeDomProvider compiler = new CSharpCodeProvider();     //编译器
        CompilerParameters comPara = new CompilerParameters();   //编译器参数
    
        comPara.GenerateExecutable = true; // 生成exe文件
        comPara.GenerateInMemory = false; // 是否在内存在输出
        comPara.OutputAssembly = "SimpleCompile.exe"; // 输出文件 
    
        compiler.CompileAssemblyFromSource(comPara, GetCode1());
        // 在当前目录生成 SimpleCompile.exe ,可直接运行
    }
    public static string GetCode1()
    {
        string code = @"using System;
                class Test
                {
                    static void Main()
                    {
                    Console.WriteLine(""Hello world"");
                    Console.ReadLine();
                    }
                }";
        return code;
    }
    

    详细下介绍可以看这里:

    public static void Test2()
    {
        CodeDomProvider compiler = new CSharpCodeProvider();     //编译器
        CompilerParameters comPara = new CompilerParameters();   //编译器参数
    
        comPara.GenerateExecutable = false;
        comPara.GenerateInMemory = true;
    
        // GetCode2() 见文末 
        CompilerResults compilerResults = compiler.CompileAssemblyFromSource(comPara, GetCode2());
    
        if (compilerResults.Errors.HasErrors)
        {
            Console.WriteLine("编译错误");
            foreach (CompilerError err in compilerResults.Errors)
            {
                Console.WriteLine(err.ErrorText);
            }
            return;
        }
    
        // 通过反射,调用HelloWorld的实例
        Assembly objAssembly = compilerResults.CompiledAssembly;
        object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
        MethodInfo objMi = objHelloWorld?.GetType().GetMethod("OutPut");
        var result = objMi?.Invoke(objHelloWorld, null);
    
        Console.WriteLine(result);
    
        // 动态类型调用 
        // 可以看到,动态调用比反射调用写法简介不少  
        dynamic dynObj = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
        var result2 = dynObj?.OutPut();
    
        Console.WriteLine(result2);
    }
    
    

    CSScript

    CSScript是C#的一个动态编译引擎。
    简介看这里:

    如果用原生的动态编译,每次都要生成一个程序集,然后通过反射的方式去调用,过于麻烦。
    如果只是想动态编译一句代码,CSScript提供了一种特别方便的写法。

    var sqr = CSScript.Evaluator
        .CreateDelegate(@"int Sqr(int a)
                            {
                                return a * a;
                            }");
    
    var r = sqr(3); // 计算3的平方 
    

    使用 CS-Script 需要安装相关Nuget包 (会安装很多东西,依赖项很多)

    Install-Package CS-Script

    • Scripting.evaluator.cs
    • Scripting.Extensions.cs
    • Scripting.native.cs

    这三个文件是 Nuget 安装 CS-Script 之后自动载入的,里面有很多实用的例子~

    有了CSScript,对原有的动态编译的调用也变得简单。

    public static void Test1()
    {
        // 得到 Assembly,反射调用
        Assembly ass = CSScript.LoadCode(GetCode2()); // GetCode2()见文末
        AsmHelper assAsmHelper = new AsmHelper(ass); 
        object obj = assAsmHelper.CreateObject("DynamicCodeGenerate.HelloWorld");
        var method = assAsmHelper.GetMethod(obj, "OutPut");
        object result = method.Invoke();
    
        // 动态调用
        dynamic obj2 = CSScript.Evaluator.LoadCode(GetCode2());
        dynamic result2 = obj2.OutPut();
    }
    

    关于CSScript的性能问题,可以参看这里:C#脚本引擎 CS-Script 之(二)——性能评测


    public static string GetCode2()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("using System;");
        sb.Append(Environment.NewLine);
        sb.Append("namespace DynamicCodeGenerate");
        sb.Append(Environment.NewLine);
        sb.Append("{");
        sb.Append(Environment.NewLine);
        sb.Append("    public class HelloWorld");
        sb.Append(Environment.NewLine);
        sb.Append("    {");
        sb.Append(Environment.NewLine);
        sb.Append("        public string OutPut()");
        sb.Append(Environment.NewLine);
        sb.Append("        {");
        sb.Append(Environment.NewLine);
        sb.Append("             return "Hello world!";");
        sb.Append(Environment.NewLine);
        sb.Append("        }");
        sb.Append(Environment.NewLine);
        sb.Append("    }");
        sb.Append(Environment.NewLine);
        sb.Append("}");
    
        string code = sb.ToString();
    
        return code;
    }
    
  • 相关阅读:
    蓝屏的钙,好喝的钙
    正则
    JavaScript 获取当前时间戳 (3种方式)
    react-native upoad imagepicker
    xmlhttprequest请求
    修改配置使fiddler可以查看https请求
    安装composer
    判定 android IOS
    看端口任务
    squid 缓存Internet 软件
  • 原文地址:https://www.cnblogs.com/jasongrass/p/10433346.html
Copyright © 2011-2022 走看看