通过Roslyn编译代码 保存内存中的编译数据并加载执行
nuget
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.14.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
<PackageReference Include="System.ValueTuple" Version="4.6.1" />
示例一 - 编译后直接加载
参考引用的文章后实现的测试代码
// See https://aka.ms/new-console-template for more information
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Mono.Cecil;
using Mono.Cecil.Rocks;
using System.Reflection;
internal class Program
{
static void Main(string[] args)
{
//string code = "int result = 1 + 2; Console.WriteLine(result);public static void TestValue(){Console.WriteLine(\"sss\");}";
string code = "using System; public class ExampleClass{ public string getMessage(){ return \"Hello World\"; } }";
//var options = ScriptOptions.Default.WithImports("System");
//var script = CSharpScript.Create(code, options);
//script.RunAsync().Wait();
//var complierResult = script.Compile();
CreateAssemblyDefinition(code);
}
// 伪代码流程
public static void CreateAssemblyDefinition(string code)
{
// 解析源代码为语法树
var syntaxTree = new CSharpLanguage().ParseText(code, SourceCodeKind.Regular);
// 系统核心引用(必须的)
var references = new List<MetadataReference>
{
// 添加系统核心库
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
// 根据情况添加其他系统库,比如:
MetadataReference.CreateFromFile(typeof(System.Console).Assembly.Location),
// 如果目标代码使用了ValueTuple,则添加
MetadataReference.CreateFromFile(typeof(ValueTuple).Assembly.Location)
};
// 创建编译对象
var compilation = new CSharpLanguage()
.CreateLibraryCompilation("InMemoryAssembly", enableOptimisations: false)
.AddReferences(references) // 添加必要程序集引用
.AddSyntaxTrees(syntaxTree); // 注入语法树
// 编译到内存流
var stream = new MemoryStream();
var emitResult = compilation.Emit(stream);
// 用Mono.Cecil读取程序集
if (emitResult.Success)
{
stream.Seek(0, SeekOrigin.Begin);
// 3. 加载程序集到运行时
byte[] assemblyBytes = stream.ToArray();
Assembly runtimeAssembly = Assembly.Load(assemblyBytes);
// 4. 创建实例并执行方法
Type exampleClassType = runtimeAssembly.GetType("ExampleClass");
if (exampleClassType == null)
{
throw new InvalidOperationException("类型 ExampleClass 未找到");
}
// 创建实例
object instance = Activator.CreateInstance(exampleClassType);
// 获取方法信息
MethodInfo getMessageMethod = exampleClassType.GetMethod("getMessage");
if (getMessageMethod == null)
{
throw new InvalidOperationException("方法 getMessage 未找到");
}
// 执行方法并输出结果
string result = (string)getMessageMethod.Invoke(instance, null);
Console.WriteLine($"执行结果: {result}");
}
}
public class CSharpLanguage : ILanguageService
{
private static readonly LanguageVersion MaxLanguageVersion = Enum
.GetValues(typeof(LanguageVersion))
.Cast<LanguageVersion>()
.Max();
public SyntaxTree ParseText(string sourceCode, SourceCodeKind kind)
{
var options = new CSharpParseOptions(kind: kind, languageVersion: MaxLanguageVersion);
// Return a syntax tree of our source code
return CSharpSyntaxTree.ParseText(sourceCode, options);
}
public Compilation CreateLibraryCompilation(string assemblyName, bool enableOptimisations)
{
// 1. 创建编译选项
var options = new CSharpCompilationOptions(
outputKind: OutputKind.DynamicallyLinkedLibrary, // 输出DLL
optimizationLevel: enableOptimisations ? OptimizationLevel.Release : OptimizationLevel.Debug,
allowUnsafe: true // 允许不安全代码
);
// 2. 创建并返回一个CSharpCompilation对象
return CSharpCompilation.Create(
assemblyName, // 程序集名称
options: options //, // 编译选项
//references: _references // 程序集引用
);
}
}
public interface ILanguageService
{
SyntaxTree ParseText(string code, SourceCodeKind kind);
Compilation CreateLibraryCompilation(string assemblyName, bool enableOptimisations);
}
}
示例二 - 编译后保存到文件 - 从文件中读取后加载
// See https://aka.ms/new-console-template for more information
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;
internal class Program
{
static void Main(string[] args)
{
//string code = "int result = 1 + 2; Console.WriteLine(result);public static void TestValue(){Console.WriteLine(\"sss\");}";
string code = "using System; public class ExampleClass{ public string getMessage(){ return \"Hello World\"; } }";
//var options = ScriptOptions.Default.WithImports("System");
//var script = CSharpScript.Create(code, options);
//script.RunAsync().Wait();
//var complierResult = script.Compile();
CreateAssemblyDefinition(code);
}
// 伪代码流程
public static void CreateAssemblyDefinition(string code)
{
// 解析源代码为语法树
var syntaxTree = new CSharpLanguage().ParseText(code, SourceCodeKind.Regular);
// 系统核心引用(必须的)
var references = new List<MetadataReference>
{
// 添加系统核心库
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
// 根据情况添加其他系统库,比如:
MetadataReference.CreateFromFile(typeof(System.Console).Assembly.Location),
// 如果目标代码使用了ValueTuple,则添加
MetadataReference.CreateFromFile(typeof(ValueTuple).Assembly.Location)
};
// 创建编译对象
var compilation = new CSharpLanguage()
.CreateLibraryCompilation("InMemoryAssembly", enableOptimisations: false)
.AddReferences(references) // 添加必要程序集引用
.AddSyntaxTrees(syntaxTree); // 注入语法树
// 编译到内存流
var stream = new MemoryStream();
var emitResult = compilation.Emit(stream);
if (emitResult.Success)
{
//将stream保存到文件
using (FileStream fs = new FileStream("InMemoryAssembly.file", FileMode.Create))
{
fs.Write(stream.ToArray(), 0, (int)stream.Length);
}
}
//var readRtream = new MemoryStream();
//readRtream.Seek(0, SeekOrigin.Begin);
//// 用Mono.Cecil读取程序集
//// 3. 加载程序集到运行时
//byte[] assemblyBytes = readRtream.ToArray();
//加载文件到内存中(模拟从数据库读取)
byte[] assemblyBytes = File.ReadAllBytes("InMemoryAssembly.file").ToArray();
Assembly runtimeAssembly = Assembly.Load(assemblyBytes);
// 4. 创建实例并执行方法
Type exampleClassType = runtimeAssembly.GetType("ExampleClass");
if (exampleClassType == null)
{
throw new InvalidOperationException("类型 ExampleClass 未找到");
}
// 创建实例
object instance = Activator.CreateInstance(exampleClassType);
// 获取方法信息
MethodInfo getMessageMethod = exampleClassType.GetMethod("getMessage");
if (getMessageMethod == null)
{
throw new InvalidOperationException("方法 getMessage 未找到");
}
// 执行方法并输出结果
string result = (string)getMessageMethod.Invoke(instance, null);
Console.WriteLine($"执行结果: {result}");
}
public class CSharpLanguage : ILanguageService
{
private static readonly LanguageVersion MaxLanguageVersion = Enum
.GetValues(typeof(LanguageVersion))
.Cast<LanguageVersion>()
.Max();
public SyntaxTree ParseText(string sourceCode, SourceCodeKind kind)
{
var options = new CSharpParseOptions(kind: kind, languageVersion: MaxLanguageVersion);
// Return a syntax tree of our source code
return CSharpSyntaxTree.ParseText(sourceCode, options);
}
public Compilation CreateLibraryCompilation(string assemblyName, bool enableOptimisations)
{
// 1. 创建编译选项
var options = new CSharpCompilationOptions(
outputKind: OutputKind.DynamicallyLinkedLibrary, // 输出DLL
optimizationLevel: enableOptimisations ? OptimizationLevel.Release : OptimizationLevel.Debug,
allowUnsafe: true // 允许不安全代码
);
// 2. 创建并返回一个CSharpCompilation对象
return CSharpCompilation.Create(
assemblyName, // 程序集名称
options: options //, // 编译选项
//references: _references // 程序集引用
);
}
}
public interface ILanguageService
{
SyntaxTree ParseText(string code, SourceCodeKind kind);
Compilation CreateLibraryCompilation(string assemblyName, bool enableOptimisations);
}
}
封装后的帮助类
public class CompileHelper
{
// 伪代码流程
public static MemoryStream CreateAssemblyDefinition(string code)
{
// 解析源代码为语法树
var syntaxTree = new CSharpLanguage().ParseText(code, SourceCodeKind.Regular);
// 系统核心引用(必须的)
var references = new List<MetadataReference>
{
// 添加系统核心库
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
// 根据情况添加其他系统库,比如:
MetadataReference.CreateFromFile(typeof(System.Console).Assembly.Location),
// 如果目标代码使用了ValueTuple,则添加
MetadataReference.CreateFromFile(typeof(ValueTuple).Assembly.Location)
};
// 创建编译对象
var compilation = new CSharpLanguage()
.CreateLibraryCompilation("InMemoryAssembly", enableOptimisations: false)
.AddReferences(references) // 添加必要程序集引用
.AddSyntaxTrees(syntaxTree); // 注入语法树
// 编译到内存流
var stream = new MemoryStream();
var emitResult = compilation.Emit(stream);
if (!emitResult.Success)
{
//emitResult.Diagnostics
throw new Exception("CompileError");
}
return stream;
}
public static void ReadStream(MemoryStream stream, string saveFile)
{
//将stream保存到文件
using (FileStream fs = new FileStream(saveFile, FileMode.Create))
{
fs.Write(stream.ToArray(), 0, (int)stream.Length);
}
}
public static void Compiling2File(string code, string saveFile)
{
var stream = CreateAssemblyDefinition(code);
ReadStream(stream, saveFile);
}
public static Assembly LoadAssemblyFromFile(string filePath)
{
//加载文件到内存中(模拟从数据库读取)
byte[] assemblyBytes = File.ReadAllBytes(filePath).ToArray();
Assembly runtimeAssembly = Assembly.Load(assemblyBytes);
return runtimeAssembly;
}
public static Assembly LoadAssemblyFromFile(byte[] assemblyBytes)
{
Assembly runtimeAssembly = Assembly.Load(assemblyBytes);
return runtimeAssembly;
}
public static Type GetClass(string filePath, string className)
{
Assembly runtimeAssembly = LoadAssemblyFromFile(filePath);
//创建实例并执行方法
Type exampleClassType = runtimeAssembly.GetType(className);
if (exampleClassType == null)
{
throw new InvalidOperationException($"ClassNotFound");
}
return exampleClassType;
}
public static Type GetClass(Assembly runtimeAssembly, string className)
{
Type exampleClassType = runtimeAssembly.GetType(className);
if (exampleClassType == null)
{
throw new InvalidOperationException($"ClassNotFound");
}
return exampleClassType;
}
public static object? ExecMethod(string filePath, string className, string methodName, object?[]? parameter = null)
{
var exampleClassType = GetClass(filePath, className);
// 创建实例
object instance = Activator.CreateInstance(exampleClassType);
// 获取方法信息
MethodInfo getMessageMethod = exampleClassType.GetMethod(methodName);
if (getMessageMethod == null)
{
throw new InvalidOperationException("MethodNotFound");
}
// 执行方法并输出结果
var result = getMessageMethod.Invoke(instance, parameter);
//Console.WriteLine($"执行结果: {result}");
return result;
}
public static object? ExecMethod(Type classType, string methodName, object?[]? parameter = null)
{
// 创建实例
object instance = Activator.CreateInstance(classType);
// 获取方法信息
MethodInfo getMessageMethod = classType.GetMethod(methodName);
if (getMessageMethod == null)
{
throw new InvalidOperationException("MethodNotFound");
}
// 执行方法并输出结果
var result = getMessageMethod.Invoke(instance, parameter);
//Console.WriteLine($"执行结果: {result}");
return result;
}
}
扩展封装
public class CompileBase
{
/// <summary>
/// 获取编译后的字节数据
/// </summary>
/// <param name="code"></param>
/// <param name="saveFile"></param>
/// <returns></returns>
public byte[] Compiling(string code, string saveFile)
{
var memStream = CompileHelper.CreateAssemblyDefinition(code);
var byteArray = new byte[memStream.Length];
var count = memStream.Read(byteArray, 0, 20);
// Read the remaining bytes, byte by byte.
while (count < memStream.Length)
{
byteArray[count++] = (byte)memStream.ReadByte();
}
return byteArray;
}
public Assembly LoadAssemblyFromFile(byte[] assemblyBytes)
{
return CompileHelper.LoadAssemblyFromFile(assemblyBytes);
}
public Type GetClass(Assembly assembly, string className)
{
var classInfo = CompileHelper.GetClass(assembly, className);
return classInfo;
}
public static object? ExecMethod(Type classType, string methodName, object?[]? parameter = null)
{
// 执行方法并输出结果
var result = CompileHelper.ExecMethod(classType, methodName, parameter);
//Console.WriteLine($"执行结果: {result}");
return result;
}
}
[参考]
In-memory C# compilation (and .dll generation) using Roslyn
留待后查,同时方便他人
联系我:renhanlinbsl@163.com
联系我:renhanlinbsl@163.com