C# 动态编译简介

共 5383字,需浏览 11分钟

 ·

2021-05-11 22:24


C# 动态类型与动态编译简介

动态类型

动态编译

CSScript

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


动态类型

关键字:dynamic

这里有详细的介绍:[C#基础知识系列]专题十七:深入理解动态类型

动态类型的应用场景


可以减少强制转换(强制转换其实挺好的,让程序猿清楚地指定自己做了什么,不至于出错时不知所措)

简化反射的写法。

与动态语言交互。

// 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\n" + "def move(n,A,B,C):\n" + " global count\n" + " if(n==1):\n" + " print(A+\"->\"+C)\n" + " count = count + 1\n" + " return\n" + " move(n - 1, A, C, B)\n" + " move(1, A, B, C)\n" + " move(n - 1, B, A, C)\n" + " return\n" + "move(5,\"A\",\"B\",\"C\")"; return code;}


动态编译

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

C#同样支持动态编译。


最主要的两个类:

CodeDomProvider 和 CompilerParameters

前者相当于编译器,后者相当于编译器参数。


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;}



详细下介绍可以看这里:


C# 动态编译

.NET Framework 中的动态编程

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#的一个动态编译引擎。

简介看这里:


C#动态编译引擎-CS-Script

CSScript.Net脚本概述

Nuget

Github

如果用原生的动态编译,每次都要生成一个程序集,然后通过反射的方式去调用,过于麻烦。

如果只是想动态编译一句代码,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;}



往期精彩回顾




【推荐】.NET Core开发实战视频课程 ★★★

.NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

【.NET Core微服务实战-统一身份认证】开篇及目录索引

Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南)

.NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

10个小技巧助您写出高性能的ASP.NET Core代码

用abp vNext快速开发Quartz.NET定时任务管理界面

在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度

现身说法:实际业务出发分析百亿数据量下的多表查询优化

关于C#异步编程你应该了解的几点建议

C#异步编程看这篇就够了


浏览 59
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报