gpt4 book ai didi

c# - 在 Roslyn 的哪个位置,作为 IL 发出的 C# 'class' 语句?

转载 作者:行者123 更新时间:2023-12-03 22:17:50 25 4
gpt4 key购买 nike

我正在尝试修改 Microsoft Roslyn 编译器以执行一些超出所提供 API 范围的奇怪操作。但我对 Roslyn 完全陌生,而且 Roslyn 非常庞大(460 万行代码),我发现很难找到适合自己的方法。

具体来说,我想找到发出“.class”IL 语句的位置,通常是执行 C# 类的最终编译,即类的外部结构。 (我发现了方法和表达式等内部内容的发出。)

编辑:

@nejcs 是正确的,在发出的代码中没有“.class”IL 语句这样的东西。我误以为您在使用 .Net Reflector 或 dotPeek 时会看到什么。

我会尝试更详细地解释我正在尝试做什么,以及我正在寻找什么,希望这能让我做我想做的事情。

考虑这样一个简单的 C# 类:

   public static class Yacks00020001
{
public static readonly string s;

static Yacks00020001()
{
s = YacksCore.M0002("Hello world!", 42);
}
}

我想要做的是在发射器处理过程中即时“创建”并发射大量这些静态对象(显然具有不同的名称和不同的字符串)。我希望通过创建足够的模拟数据来“愚弄”发出类声明、方法和语句的发射器方法,并使用这个模拟输入调用它们来做到这一点。

我想我在编译期间找到了描述 C# 类声明的对象,它在这里:

https://github.com/dotnet/roslyn/blob/45f6e9bc6dd457a5279f0f1b380a70ca8ac0a59d/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs

它是在这里创建的:

https://github.com/dotnet/roslyn/blob/45f6e9bc6dd457a5279f0f1b380a70ca8ac0a59d/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs#L343

但我不是 100% 确定这一点。

尽管@nejcs 在他的回答中提供了很好的信息,但我仍然找不到发射器处理类声明的位置。

最佳答案

没有 .class IL 语句。您指的是用于类声明的 IL 汇编程序 (ilasm) 指令。程序集中类的实际声明位于特定部分,不由任何关键字标识。有关 CLR 部分的详细说明,我建议阅读 part1part2 .

因为类只是声明,所以也没有类的编译。只有当你想发送到 PE 流时,你必须检索所有声明的类型、方法和其他对象,以将它们写入流中的正确位置。所以编译是这样的:

  1. 让我们从CompileAndEmit开始方法。此方法执行编译并发出最终程序集。
  2. 如果没有解析错误,module builder is created .对于 C# 覆盖 CreateModuleBuilder将调用 PEAssemblyBuilder 并存储对编译的源程序集符号的引用,该符号包含所有其他符号,包括类。
  3. CompileAndEmit 调用方法体的编译并将结果存储到模块构建器。
  4. 如果一切成功,CompileAndEmit serialises module builder to PE stream .经过一些设置 SerializePeToStream被调用,它创建 EmitContext,其中包含传递给元数据编写器的模块构建器引用。 Writer 使用模块构建器提取有关类和其他对象的信息,并为最终存储创建适当的索引。

简而言之,Compilation 类(CSharpCompilation 用于 C# 代码)为程序集生成器提供源程序集符号,然后将其传递并可以查询各种对象。我不知道你想要实现什么,但你可能想要修改存储在 Compilation 本身中的内容,因为管道中没有太多逻辑。不过,我可能漏掉了什么。

编辑

根据问题编辑,我将更详细地描述元数据编写器如何提取有关类的信息。为简化起见,我将专注于编写完整元数据并忽略差异元数据。

  1. 如果我们从 SerializePeToStreamMethod 继续,将创建完整的元数据编写器并且 BuildMetadataAndIL被称为。
  2. 此方法将调用 CreateIndices它负责创建将序列化为 PE 的内部结构。我们感兴趣CreateIndicesForModule方法。
  3. CreateIndicesForModule 检索 top level types , 通过最终调用 GetTopLevelTypeCommonPEModuleBuilder 上。您可以看到有多种类型被检索,但我们对 GetTopLevelTypesCore 方法感兴趣。
  4. GetTopLevelTypesCore返回顶级类型并遍历所有命名空间符号并返回子类型。此时,当元数据编写器设置其内部结构以进行序列化时,您会看到直接从编译符号中检索类型。

至于你的具体问题,我仍然认为生成有效的编译对象(具有正确的符号)并保持发射阶段不变会更好。否则,您必须非常小心数据处于一致状态,否则您将遇到异常或无效 PE。

关于c# - 在 Roslyn 的哪个位置,作为 IL 发出的 C# 'class' 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48718624/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com