C# 动态类型与动态编译简介
关于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;
}
详细下介绍可以看这里:
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;
}
C# 动态类型与动态编译简介的更多相关文章
- OC 动态类型,动态绑定,动态加载
OC 动态类型,动态绑定,动态加载 Objective-C具有相当多的动态特性,基本的,也是经常被提到和用到的有 动态类型(Dynamic typing) 动态绑定(Dynamic binding) ...
- 《精通C#》第十六章-动态类型和动态语言运行时-第一节至第四节
在.Net4.0中引入了一个关键字dynamic,这是一个动态类型关键字.Net中还有一个关键字是var,这是一个隐式类型,可以定义本地变量,此时var所代表的实际的数据类型有编译器在初次分配时决定, ...
- C# 4.0中的动态类型和动态编程
# 4.0的主题就是动态编程(Dynamic Programming).虽然C#仍然是一种静态语言,但是对象的意义开始变得越来越“动态”.它们的结构和行为无法通过静态类型来捕获,或者至少编译器在编译程 ...
- 动态类型识别&动态创建
以下大部分内容摘自<windows程序设计 第2版> 王艳平 张铮 编著 动态类型识别:在程序运行过程中,辨别对象是否属于特定类的技术. 应用举例:函数辨别参数类型.需要针对对象的类编写特 ...
- C#学习笔记(十一):动态类型
C#是一门静态类型的语言,但是在C#4.0时微软引入了动态类型的概念. dynamic 关键字dynamic用来定义动态对象,我们来看一下动态类型的一些特性. 调用不同类的相同方法 我们有两个或多个不 ...
- C# 匿名对象(匿名类型)、var、动态类型 dynamic
本文是要写的下篇<C#反射及优化用法>的前奏,不能算是下一篇文章的基础的基础吧,有兴趣的朋友可以关注一下. 随着C#的发展,该语音内容不断丰富,开发变得更加方便快捷,C# 的锋利尽显无疑. ...
- C# 匿名对象(匿名类型)、var、动态类型 dynamic——实用之:过滤类属性、字段实用dynamic
例子 返回一个LIst<oject>类型 而oject含有 30个字段 而我只需要两个字段.这里实用dynamic 和 linq. 上代码: 注意select new {} 为匿名类型,这 ...
- 面向对象的JavaScript --- 动态类型语言
面向对象的JavaScript --- 动态类型语言 动态类型语言与面向接口编程 JavaScript 没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承. Jav ...
- 静态类型&动态类型
何时使用:使用存在继承关系的类型时,必须将一个变量或其他表达式的静态类型与该表达式表示对象的动态类型区分开来 静态类型:表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型 动态 ...
随机推荐
- 【BZOJ】3453: tyvj 1858 XLkxc 拉格朗日插值(自然数幂和)
[题意]给定k<=123,a,n,d<=10^9,求: $$f(n)=\sum_{i=0}^{n}\sum_{j=1}^{a+id}\sum_{x=1}^{j}x^k$$ [算法]拉格朗日 ...
- Java后台获取前端utf-8格式 ;空格,使用trim()消除不了的解决办法
byte bytes[] = {(byte) 0xC2,(byte) 0xA0}; String UTFSpace = new String(bytes,"utf-8"); htm ...
- spring断言使用
断言就是断定某一个实际的值为自己预期想得到的,如果不一样就抛出异常. Assert经常用于: 1.判断method的参数是否属于正常值.2.juit中使用. import org.springfram ...
- CF448C Painting Fence
传送门 Descriptionzed 最近总是受到 Farmer 的困扰,因此他在自家的门前插了一排栅栏以防农气的入侵.栅栏由 N 个竖条栅栏横向组成,每个竖条栅栏宽度为 1.过了一段时间,zed 觉 ...
- Jenkins02:Jenkins+maven+svn集成
1.安装Maven并配置环境变量 下载maven(windows下载zip包,linux下载tar.gz包),然后配置环境变量 在项目中使用maven,可以从java中央仓库中获取到项目所依赖的jar ...
- 【译】第八篇 SQL Server代理使用外部程序
本篇文章是SQL Server代理系列的第八篇,详细内容请参考原文 在这一系列的上一篇,学习了如何用SQL Server代理作业活动监视器监控作业活动和查看作业历史记录.在实时监控和管理SQL Ser ...
- Spring笔记13--SSH--全注解开发
SSH全注解开发: (1) 在Action类中添加注解,实现Struts2的注解开发(@NameSpace.@ParentPackage.@Action...) package com.tongji. ...
- 微信小程序实战--开发一个简单的快递单号查询
功能如图: 虽然工作中只负责小程序后台开发,但是还是小程序开发产生了浓厚的兴趣,官方文档也是超级详细了 这里就简单做一个快递单号的查询: 新建一个page: 接着就可以写wxml了.这里用一个简单的i ...
- JDK 6和JDK 7的intern方法之不同
首先介绍下intern方法: 如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回. 1 2 在<深入理解Java虚拟机> ...
- Codeforces Round #504 E. Down or Right
Codeforces Round #504 E. Down or Right 题目描述:交互题. 有一个\(n \times n\)的方阵,有一些格子是障碍,从\((1, 1)\)出发,只能向右向下走 ...