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);
}
}
[参考]
In-memory C# compilation (and .dll generation) using Roslyn
留待后查,同时方便他人