
使用CodeDom动态生成类型
发布日期:2021-05-09 04:12:30
浏览次数:14
分类:博客文章
本文共 5266 字,大约阅读时间需要 17 分钟。
.NET 3.5的时候加入了匿名类型这个特性,我们可以直接使用 new {name="abc"} 来直接生成一个对象。这个特性现在应用的地方很多,比如dapper的查询参数都是用匿名对象。
其实匿名对象也不是真的没有名称,编译器在编译后自动会生成一个Type。我们看看IL就知道了。编译器会自动生成一个叫做<>f__AnonymousType0`1的类型。动态生成类型
但是有的时候我们可能类型里面的字段都是不确定的,这个时候我们就需要去动态生成一个类型了。
- 动态生成类型第一个想到的就是反射,但是仔细想想反射都是基于现有Type的基础上完成的,咱们现在连Type都没有,所以这条路不通。
- 第二个dynamic,dynamic确实是个好办法,可以动态指定字段的名称,但是有的三方的库不支持比如dapper。
- 最后CodeDom,CodeDom可以在运行时直接生成一个Type。CodeDom生成Type主要分成3步。比如我们要生成一个Person类:
public class Person{ public string name; public ing age; public Person(string name ,int age) { this.name = name; this.age = age; }}
构造类型
private string _ns = "__x"; private string _className; private Dictionary_fieldsDictionary; private string _sourceCode; private CodeCompileUnit _targetUnit; private CodeTypeDeclaration _targetClass; public SourceCodeCreater(string className,Dictionary fieldsDictionary ) { _fieldsDictionary = fieldsDictionary; _className = className; _targetUnit = new CodeCompileUnit(); CodeNamespace ns = new CodeNamespace(_ns); ns.Imports.Add(new CodeNamespaceImport("System")); _targetClass = new CodeTypeDeclaration(className); _targetClass.IsClass = true; _targetClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed; ns.Types.Add(_targetClass); _targetUnit.Namespaces.Add(ns); } public string SourceCode { get { return _sourceCode; } } public string TypeName { get { return string.Format("{0}.{1}", _ns, _className); } } private void AddFields() { // Declare fields . foreach (var kv in _fieldsDictionary) { CodeMemberField widthValueField = new CodeMemberField(); widthValueField.Attributes = MemberAttributes.Public; widthValueField.Name = kv.Value; widthValueField.Type = new CodeTypeReference(kv.Key); _targetClass.Members.Add(widthValueField); } } private void AddCtor() { // Declare constructor CodeConstructor constructor = new CodeConstructor(); constructor.Attributes = MemberAttributes.Public | MemberAttributes.Final; // Add parameters. foreach (var kv in _fieldsDictionary) { constructor.Parameters.Add(new CodeParameterDeclarationExpression( kv.Key, kv.Value)); } // Add field initialization logic foreach (var kv in _fieldsDictionary) { CodeFieldReferenceExpression reference = new CodeFieldReferenceExpression( new CodeThisReferenceExpression(), kv.Value); constructor.Statements.Add(new CodeAssignStatement(reference, new CodeArgumentReferenceExpression(kv.Value))); } _targetClass.Members.Add(constructor); }
我们按照手写类的结构添加字段跟构造函数。
生成CSharp代码
public string Create() { AddFields(); AddCtor(); CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp"); CodeGeneratorOptions options = new CodeGeneratorOptions(); options.BracingStyle = "C"; using (StringWriter sourceWriter = new StringWriter()) { provider.GenerateCodeFromCompileUnit( _targetUnit, sourceWriter, options); _sourceCode = sourceWriter.ToString(); } return _sourceCode; }
生成CSharp代码
编译
SourceCodeCreater sourceCodeCreater =new SourceCodeCreater(className,fields); var sourceCode = sourceCodeCreater.Create(); Console.WriteLine(sourceCode); var typeName = sourceCodeCreater.TypeName; CSharpCodeProvider p = new CSharpCodeProvider(); CompilerParameters param = new CompilerParameters(new string[] { "System.dll" }); CompilerResults rel = p.CompileAssemblyFromSource(param, sourceCode); Type t = rel.CompiledAssembly.GetType(typeName);
编译代码获得Type
运行一下
static void Main(string[] args) { var className = "Person"; var fields =new Dictionary(); fields.Add(typeof(string),"name"); fields.Add(typeof(int),"age"); SourceCodeCreater sourceCodeCreater =new SourceCodeCreater(className,fields); var sourceCode = sourceCodeCreater.Create(); Console.WriteLine(sourceCode); var typeName = sourceCodeCreater.TypeName; CSharpCodeProvider p = new CSharpCodeProvider(); CompilerParameters param = new CompilerParameters(new string[] { "System.dll" }); CompilerResults rel = p.CompileAssemblyFromSource(param, sourceCode); Type t = rel.CompiledAssembly.GetType(typeName); Console.WriteLine(t.FullName); foreach (var f in t.GetFields()) { Console.WriteLine("Type:{0} Name:{1}",f.FieldType,f.Name); } Console.Read(); }
参考
发表评论
最新留言
第一次来,支持一个
[***.219.124.196]2025年04月05日 13时23分57秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
POD类型
2021-05-09
Head First设计模式——迭代器模式
2021-05-09
记一次讲故事机器人的开发-我有故事,让机器人来读
2021-05-09
netcore中使用session
2021-05-09
远程触发Jenkins的Pipeline任务的并发问题处理
2021-05-09
【wp】HWS计划2021硬件安全冬令营线上选拔赛
2021-05-09
Ef+T4模板实现代码快速生成器
2021-05-09
Java面试题:Servlet是线程安全的吗?
2021-05-09
Linux探测工具BCC(可观测性)
2021-05-09
采坑 - 字符串的 "" 与 pd.isnull()
2021-05-09
《我是猫》总结
2021-05-09
mcrypt加密以及解密过程
2021-05-09
go等待N个线程完成操作总结
2021-05-09
Python 之网络式编程
2021-05-09
SpringCloud微服务(03):Hystrix组件,实现服务熔断
2021-05-09
网站故障公告1:使用阿里云RDS之后一个让人欲哭无泪的下午
2021-05-09
[网站公告]又拍云API故障造成图片无法上传(已恢复)
2021-05-09
上周热点回顾(6.9-6.15)
2021-05-09
.NET跨平台之旅:借助ASP.NET 5 Beta5的新特性显示CLR与操作系统信息
2021-05-09
上周热点回顾(5.9-5.15)
2021-05-09