宝塔山 发表于 2024-12-20 15:16:36

CompilerGenerated与GeneratedCode区别

前言

迩来在捣鼓代码天生器,基于 Roslyn,我们可以让天生器项目天生我们的目的 C# 代码,这个也是MVVM Toolkit的实现方式,在检察天生代码的过程中,我们经常会碰到一些特殊的特性,如 GeneratedCodeAttribute ,刚好我还碰到过 CompilerGeneratedAttribute。感觉两个特性差不多,都可以用于标识代码的天生来源,帮助开发者和其他工具更好地理解和处理代码。
GeneratedCodeAttribute 解析

定义与用途

GeneratedCodeAttribute 是一个系统提供的特性,定义在 System.CodeDom.Compiler 命名空间,用于标记由工具或编译器天生的代码。它通常包含两个参数:天生工具的名称和版本号。

public sealed class GeneratedCodeAttribute : Attribute
{
    public string Tool { get; }
    public string Version { get; }

    public GeneratedCodeAttribute(string tool, string version)
    {
      Tool = tool;
      Version = version;
    }
}这个特性的主要用途是:

[*]标识天生的代码:当你使用 Source Generator、T4 模板、Roslyn API 或其他代码天生工具时,可以在天生的文件中添加这个特性,以明确指出代码是由哪个工具天生的。
[*]避免误修改:标记为 GeneratedCode 的代码可以提醒开发者不要直接编辑这些文件,因为它们是主动天生的,任何手动修改可能会在下次天生时丢失。
[*]分析器和工具支持:某些分析器(如 Roslyn 分析器)和工具会辨认并特殊处理带有 GeneratedCodeAttribute 的代码,例如忽略代码覆盖率统计或特定的代码分析规则。
示例

假设你有一个 Source Generator 工具名为 MyCustomTool,版本为 1.0.0,你可以这样标记天生的代码:

public partial class MyClass
{
    // 自动生成的代码
}CompilerGeneratedAttribute 解析

定义与用途

CompilerGeneratedAttribute 定义在 System.Runtime.CompilerServices 命名空间,是一个更具体的特性,用于标记由 C# 编译器主动天生的代码片段。它没有参数,仅表示代码是由编译器天生的。

public sealed class CompilerGeneratedAttribute : Attribute
{
}这个特性的主要用途是:

[*]标识编译器天生的代码:当编译器为了实现某些语言特性(如匿名类型、迭代器、异步方法等)而主动天生代码时,会主动添加这个特性。这有助于区分用户编写的代码和编译器天生的代码。
[*]内部实现细节:这个特性主要用于内部实现细节,普通开发者通常不需要手动添加它。它是编译器用来标记其天生的代码的一种方式。
示例

编译器天生的代码片段可能如下所示:

private sealed class <>c__DisplayClass1_0
{
    public int x;

    internal void <Method>b__0()
    {
      Console.WriteLine(x);
    }
}区别与选择

虽然 GeneratedCodeAttribute 和 CompilerGeneratedAttribute 都用于标识代码的天生来源,但它们有着差别的用途和适用场景。

[*]来源差别:

[*]GeneratedCodeAttribute 通常由外部工具或源代码天生器添加,以标识代码是由某个工具天生的,一般来说是出于编码职员的自身目的。
[*]CompilerGeneratedAttribute 由 C# 编译器自身添加,用于标识编译器天生的代码片段。

[*]应用场景:

[*]如果你正在开发 Source Generator 或其他代码天生工具,并希望标记天生的代码以便后续处理或提醒开发者不要直接编辑这些文件,应该手动标记使用 GeneratedCodeAttribute。
[*]不应该手动添加该特性,如果你在检察编译后的代码,发现带有 CompilerGeneratedAttribute 的类或成员,这通常是编译器为了实现某些语言特性而天生的代码,不应被手动修改。

代码天生器应用示例

MVVM Toolkit 就按照这个标准开发,假设你正在开发一个 Source Generator 来天生部分类文件:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.CodeDom.Compiler;

public class MySourceGenerator : ISourceGenerator
{
    public void Initialize(GeneratorInitializationContext context)
    {
      // Initialization logic if needed
    }

    public void Execute(GeneratorExecutionContext context)
    {
      var sourceBuilder = new StringBuilder();
      sourceBuilder.AppendLine("");
      sourceBuilder.AppendLine("public partial class MyClass");
      sourceBuilder.AppendLine("{");
      sourceBuilder.AppendLine("    public string MyProperty { get; set; }");
      sourceBuilder.AppendLine("}");

      context.AddSource("MyClass.g.cs", sourceBuilder.ToString());
    }
}上面代码中,GeneratedCodeAttribute 被用来标记天生的代码,确保其他工具和开发者知道这段代码是由 MyCustomTool 天生的。
一些发起:

[*]不适用于用户可修改的模板:如果有一个代码天生工具天生的模板,用户可能会根据需要对其进行修改,那么就不应该使用 GeneratedCodeAttribute 标记这些模板。因为一旦代码被手动修改,再用 GeneratedCodeAttribute 标记就不再准确了,而且可能会误导其他工具忽略这些手动修改的内容。


[*]部分类的特殊处理:当天生的代码是部分类的一部分时,不要在整个类上应用 GeneratedCodeAttribute。相反,你应该仅将此特性应用于该部分类中天生的具体成员(如方法、字段、属性等)。这是因为部分类可以有多个文件定义,而用户可能在其他文件中添加自己的实现。通过只标记天生的成员,你可以确保只有主动天生的部分被正确标识,而不会影响用户添加的代码。(这个可以看 MVVM Toolkit 天生的代码)
总结

简单说来:

[*]GeneratedCodeAttribute 主要用于标记由工具或编译器天生的代码,特别是那些会频仍重新天生的代码。这有助于开发者和其他工具辨认这些代码片段,并避免对它们进行不必要的修改。
[*]CompilerGeneratedAttribute 一般不要手动添加到代码中。
参考文献


[*]Microsoft Docs: GeneratedCodeAttribute
[*]Microsoft Docs: CompilerGeneratedAttribute
[*]Correct usage of the CompilerGeneratedAttribute and the GeneratedCodeAttribute | Microsoft Learn

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: CompilerGenerated与GeneratedCode区别