.net 动态编译

记录一下初次使用动态编译的部分代码,最后会将反编译之后的完整代码贴在文章末尾.

需要用到的程序集/Nuget

因为是第一次使用动态编译,找资料时需要以下的两个包
System.CodeDom
Microsoft.CSharp


不过我的项目是基于 .NetCore 在最后编译成dll 时无法编译,后来使用以下两个包替换掉了Microsoft.CSharp
Microsoft.CodeAnalysis
Microsoft.CodeAnalysis.CSharp


所以此文主要的基于 .netcoreMicrosoft.CodeAnalysis

CodeCompileUnit

官方定义: 为 CodeDOM 程序图形提供容器。
样例:

var gCompile = new CodeCompileUnit(); 

CodeNamespace

官方定义: 表示命名空间声明
样例:

var gNamespace = new CodeNamespace("Project.Import") `
//添加引用
gNamespace.Imports.Add(new CodeNamespaceImport("System.Text"));
//将此命名空间添加到容器中: 
gCompile.Namespaces.Add(gNamespace);

CodeMemberMethod

官方定义: 表示某种类型的方法的声明

CodeTypeReference

官方定义: 表示对某类型的引用

CodeParameterDeclarationExpression

官方定义: 表示方法、属性或构造函数的参数声明

CodeSnippetStatement

官方定义 使用原义代码片段表示一条语句
样例:

// 声明一个方法
var method = new CodeMemberMethod()
{
	Name = "InitCustomParam",
	Attributes = MemberAttributes.Private | MemberAttributes.Final,
	Parameters =
	{
		new CodeParameterDeclarationExpression(typeof(IEnumerable<string>), "fields")
	},
	ReturnType = new CodeTypeReference(typeof(string))
};
// 构建方法体, 方法体比较复杂, 这里采用的是 字符串拼接
var statement = new StringBuilder();
statement.AppendLine("var sb = new  StringBuilder();");
statement.AppendLine("sb.Append(\"{\");");
statement.AppendLine("var _index = 0;");
statement.AppendLine("foreach (var item in fields)");
statement.AppendLine("{");
statement.AppendLine("var val = this.GetType().GetProperty(item).GetValue(this);");
statement.AppendLine("if(fields.Count()-1==_index)");
statement.AppendLine("sb.Append(string.Format(\"\\\"{0}\\\":\\\"{1}\\\"\", item, val));");
statement.AppendLine("else");
statement.AppendLine("sb.Append(string.Format(\"\\\"{0}\\\":\\\"{1}\\\",\", item, val));");
statement.AppendLine("_index++;");
statement.AppendLine("}");
statement.AppendLine("sb.Append(\"}\");");
statement.Append("return sb.ToString();");
method.Statements.Add(new CodeSnippetStatement(statement.ToString()));
// 将方法添加到 class 中
gClass.Members.Add(method);

CodeMemberField

官方定义: 表示某种类型的字段的声明

CodeArrayCreateExpression

官方定义: 表示创建数组的表达式

CodePrimitiveExpression

官方定义: 表示基元数据类型的值

// 声明一个字段
var gField4Param = new CodeMemberField(typeof(string[]), "_ParamFields");
gField4Param.Attributes = MemberAttributes.Private | MemberAttributes.Final;
// 默认值
gField4Param.InitExpression = new CodeArrayCreateExpression(typeof(string), properties.Select(p => new CodePrimitiveExpression(p)).Cast<CodeExpression>().ToArray());
// 将字段添加到 class 中
gClass.Members.Add(gField4Param);

CodeMemberProperty

官方定义: 表示某种类型的属性的声明

CodeMethodReturnStatement

官方定义: 表示返回值语句

CodeMethodInvokeExpression

官方定义: 表示调用方法的表达式

CodeThisReferenceExpression

官方定义: 表示对当前本地类实例的引用

CodeFieldReferenceExpression

官方定义: 表示对某字段的引用

CodeAttributeDeclaration

官方定义: 表示特性声明

// 声明一个属性
var gProperty4CustomizeParam = new CodeMemberProperty()
{
	Name = "CustomizeParam",
	Attributes = MemberAttributes.Public | MemberAttributes.Final,
	// 类型
	Type = new CodeTypeReference(typeof(string)),
	// get 访问器
	GetStatements =
	{
		new CodeMethodReturnStatement(
			new CodeMethodInvokeExpression(new CodeThisReferenceExpression(),
				method.Name,
				new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), gField4Param.Name)
				))
	},
	// 添加特性
	CustomAttributes = { new CodeAttributeDeclaration(new CodeTypeReference(typeof(IEIgnoreAttribute))) }
};
// 将属性添加到 class 中
gClass.Members.Add(gProperty4CustomizeParam);

CodeAssignStatement

官方定义: 表示简单的赋值语句

CodePropertySetValueReferenceExpression

官方定义: 表示属性集方法内的属性集方法调用的值参数

CodeAttributeArgument

官方定义: 表示在元数据特性声明中使用的参数

// 常规的属性字段声明
foreach (var item in properties)
{
	/* field */
	var field = new CodeMemberField(typeof(string), $"_{item}");
	/* property */
	var property = new CodeMemberProperty()
	{
		Name = item,
		Attributes = MemberAttributes.Public | MemberAttributes.Final,
		Type = new CodeTypeReference(typeof(string)),
		GetStatements =
		{
			new CodeMethodReturnStatement(
				new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), $"_{item}" ))
		},
		SetStatements =
		{
			new CodeAssignStatement(
				new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), $"_{item}"),
				new CodePropertySetValueReferenceExpression())
		}
	};
	property.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(ImporterHeaderAttribute)),
		new CodeAttributeArgument("Name", new CodePrimitiveExpression(item)),
		new CodeAttributeArgument("Description", new CodePrimitiveExpression(item))));
	gClass.Members.Add(field);
	gClass.Members.Add(property);
}

代码编译成 dll

var sb = new StringBuilder();
var tx = new StringWriter(sb);
CodeDomProvider.CreateProvider("CSharp").GenerateCodeFromCompileUnit(compileUnit, tx, new CodeGeneratorOptions()
{
	BracingStyle = "C",
	IndentString = "    "
});
var syntaxTree = SyntaxFactory.ParseSyntaxTree(sb.ToString());
var references = GetReferences(); // GetReferences(); 获取需要的引用
var compilation = CSharpCompilation.Create(creationDllName) // creationDllName 生成的dll文件名
	.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) //OutputKind.DynamicallyLinkedLibrary 生成的文件类型
	.AddSyntaxTrees(syntaxTree)
	.AddReferences(references);
var emitResult = compilation.Emit(outPath); // outPath dll 保存路径
// 最终通过 emitResult.Success 来判断编译是否成功
// 获取引用集
private static IEnumerable<MetadataReference> GetReferences()
{
	var references = new List<MetadataReference>();
	var locations = new List<string>();
	#region system reference
	var refLocation = typeof(object).GetTypeInfo().Assembly.Location;
	var basePath = Directory.GetParent(refLocation);
	locations.Add(refLocation);
	refLocation = Path.Combine(basePath.FullName, "System.dll");
	locations.Add(refLocation);
	refLocation = typeof(JsonSerializer).Assembly.Location;
	locations.Add(refLocation);
	// ........
	#endregion
	references.AddRange(locations.Select(x => MetadataReference.CreateFromFile(x)).ToList());
	return references;
}

贴一下反编译之后的源码内容

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Magicodes.ExporterAndImporter.Core;

public class PurchaseImportInfo
{
	private string _Name;

	private string _Age;

	private string _Address;

	private string[] _ParamFields = new string[3]
	{
		"Name",
		"Age",
		"Address"
	};

	[ImporterHeader(Name = "Name", Description = "Name")]
	public string Name
	{
		get
		{
			return _Name;
		}
		set
		{
			_Name = value;
		}
	}

	[ImporterHeader(Name = "Age", Description = "Age")]
	public string Age
	{
		get
		{
			return _Age;
		}
		set
		{
			_Age = value;
		}
	}

	[ImporterHeader(Name = "Address", Description = "Address")]
	public string Address
	{
		get
		{
			return _Address;
		}
		set
		{
			_Address = value;
		}
	}

	[IEIgnore]
	public string CustomizeParam => InitCustomParam(_ParamFields);

	private string InitCustomParam(global::System.Collections.Generic.IEnumerable<string> fields)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		StringBuilder val = new StringBuilder();
		val.Append("{");
		int num = 0;
		global::System.Collections.Generic.IEnumerator<string> enumerator = fields.GetEnumerator();
		try
		{
			while (((global::System.Collections.IEnumerator)enumerator).MoveNext())
			{
				string current = enumerator.get_Current();
				object value = base.GetType().GetProperty(current).GetValue((object)this);
				if (Enumerable.Count<string>(fields) - 1 == num)
				{
					val.Append($"\"{current}\":\"{value}\"");
				}
				else
				{
					val.Append($"\"{current}\":\"{value}\",");
				}
				num++;
			}
		}
		finally
		{
			((global::System.IDisposable)enumerator)?.Dispose();
		}
		val.Append("}");
		return ((object)val).ToString();
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值