You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否提取Reflection.Emit创建的程序集中的类并物理保存,无需反编译工具?

答案:当然可以!分两步实现,无需外部反编译工具

嘿,这个问题我刚好折腾过,给你捋捋清楚:

第一步:把Reflection.Emit生成的程序集保存到磁盘

其实Reflection.Emit本身就支持直接把动态程序集存到指定路径,根本不需要额外工具。关键是创建AssemblyBuilder的时候,要指定允许保存的访问模式(AssemblyBuilderAccess.RunAndSave或者Save),之后调用Save方法就能生成.dll或.exe文件了。

给你个简单的示例代码:

using System.Reflection;
using System.Reflection.Emit;
using System.IO;

var assemblyName = new AssemblyName("MyDynamicAssembly");
// 重点:用RunAndSave模式,既可以运行也可以保存
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
// 定义模块,第二个参数是保存后的文件名
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, "MyDynamicAssembly.dll");

// 随便定义一个测试类和方法
var typeBuilder = moduleBuilder.DefineType("MyDynamicClass", TypeAttributes.Public);
var helloMethod = typeBuilder.DefineMethod(
    "PrintHello",
    MethodAttributes.Public | MethodAttributes.Static,
    typeof(void),
    Type.EmptyTypes);

var ilGenerator = helloMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldstr, "Hi from my dynamic class!");
ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(string) })!);
ilGenerator.Emit(OpCodes.Ret);

// 完成类型创建
typeBuilder.CreateType();

// 指定保存路径,比如当前目录下的Output文件夹
string outputDir = Path.Combine(Environment.CurrentDirectory, "DynamicProject");
Directory.CreateDirectory(outputDir);
string assemblyPath = Path.Combine(outputDir, "MyDynamicAssembly.dll");
assemblyBuilder.Save(assemblyPath);

Console.WriteLine($"程序集已保存到:{assemblyPath}");

第二步:提取类并生成可读代码(无需外部反编译)

这里分两种情况来处理:

情况1:你自己生成动态程序集——同步生成源代码最省心

如果你是自己用Reflection.Emit写的代码,其实完全可以在生成IL的同时,用Roslyn(.NET官方的代码分析库)同步生成对应的C#源代码,这样直接就能保存成.cs文件,比事后提取方便多了。

比如,在定义完动态类后,同时生成对应的C#类代码:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

// 用Roslyn生成C#类语法树
var classSyntax = SyntaxFactory.ClassDeclaration("MyDynamicClass")
    .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
    .AddMembers(
        SyntaxFactory.MethodDeclaration(SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), "PrintHello")
            .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword))
            .AddBodyStatements(
                SyntaxFactory.ExpressionStatement(
                    SyntaxFactory.InvocationExpression(
                        SyntaxFactory.MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            SyntaxFactory.IdentifierName("Console"),
                            SyntaxFactory.IdentifierName("WriteLine")))
                    .AddArgumentListArguments(
                        SyntaxFactory.Argument(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal("Hi from my dynamic class!"))))
                )
            );

// 生成代码文本
var code = classSyntax.NormalizeWhitespace().ToFullString();
// 保存到.cs文件
string codePath = Path.Combine(outputDir, "MyDynamicClass.cs");
File.WriteAllText(codePath, code);

情况2:已有的动态程序集——提取IL或用Roslyn转译

如果是已经生成好的程序集,没有同步保存源代码,.NET内置API没法直接把IL转成漂亮的C#,但你可以:

  • 提取IL代码:通过MethodBody.GetILAsByteArray()获取方法的IL字节,虽然可读性差,但也是代码的一种形式;
  • 用Roslyn的高级API解析程序集元数据,手动生成C#代码:这需要对Roslyn和.NET元数据有一定了解,比较繁琐,但完全可以做到,不需要外部工具。

另外,如果你想生成完整的.NET项目,只要手动创建一个.csproj文件(就是个XML),把生成的.cs文件放进去就行,比如:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>
</Project>

把这个内容保存成DynamicProject.csproj放到之前的DynamicProject文件夹里,就构成一个可以直接编译运行的项目了。

总结

  • 保存动态程序集到磁盘:完全没问题,Reflection.Emit自带支持;
  • 生成带代码的项目:自己生成的话同步用Roslyn写源代码最方便;已有程序集的话,不用外部工具可以提取IL,转C#需要用Roslyn做一些解析工作。

内容的提问来源于stack exchange,提问作者Youssef ab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:00:00