前言

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

GeneratedCodeAttribute 解析

定义与用途

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

[AttributeUsage(AttributeTargets.All, Inherited = false)]
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,你可以这样标记生成的代码:

[GeneratedCode("MyCustomTool", "1.0.0")]
public partial class MyClass
{
// 自动生成的代码
}

CompilerGeneratedAttribute 解析

定义与用途

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

[AttributeUsage(AttributeTargets.All, Inherited = false)]
public sealed class CompilerGeneratedAttribute : Attribute
{
}

这个特性的主要用途是:

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

示例

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

[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public int x; internal void <Method>b__0()
{
Console.WriteLine(x);
}
}

区别与选择

虽然 GeneratedCodeAttributeCompilerGeneratedAttribute 都用于标识代码的生成来源,但它们有着不同的用途和适用场景。

  • 来源不同

    • 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("[GeneratedCode(\"MyCustomTool\", \"1.0.0\")]");
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 一般不要手动添加到代码中。

参考文献

CompilerGenerated与GeneratedCode区别的更多相关文章

  1. Java中serialVersionUID的解释及两种生成方式的区别(转载)

    转载自:http://blog.csdn.net/xuanxiaochuan/article/details/25052057 serialVersionUID作用:        序列化时为了保持版 ...

  2. 从yield关键字看IEnumerable和Collection的区别

    C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的.相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制.但是即使你知道这个机制,你也很容易 ...

  3. c#与java的区别

    经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...

  4. jquery和Js的区别和基础操作

    jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...

  5. 【原】nodejs全局安装和本地安装的区别

    来微信支付有2年多了,从2年前的互联网模式转变为O2O模式,主要的场景是跟线下的商户去打交道,不像以往的互联网模式,有产品经理提需求,我们帮忙去解决问题. 转型后是这样的,团队成员更多需要去寻找业务的 ...

  6. 探究@property申明对象属性时copy与strong的区别

    一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...

  7. X86和X86_64和X64有什么区别?

    x86是指intel的开发的一种32位指令集,从386开始时代开始的,一直沿用至今,是一种cisc指令集,所有intel早期的cpu,amd早期的cpu都支持这种指令集,ntel官方文档里面称为&qu ...

  8. Java中Comparable与Comparator的区别

    相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...

  9. MySQL中interactive_timeout和wait_timeout的区别

    在用mysql客户端对数据库进行操作时,打开终端窗口,如果一段时间没有操作,再次操作时,常常会报如下错误: ERROR (HY000): Lost connection to MySQL server ...

  10. 设置line-height:1.5和line-height:150%或者line-height:150px的区别

    直接正题: 看一下line-height可能的值: 其实可以分为两类: (1)不带单位的(如line-height:1.5),这种是推荐使用的: (2)带单位的(如line-heigth:30px/1 ...

随机推荐

  1. 【赵渝强老师】Oracle的PGA与数据库连接建立的过程

    首先,我们来了解一下Oracle的内存结构,如下: 关于Oracle的内存结构,详情请查看:[赵强老师]Oracle数据库的内存结构 (一)PGA的组成结构 PGA主要由以下三部分组成: 私有SQL区 ...

  2. 全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用

    全网最适合入门的面向对象编程教程:56 Python 字符串与序列化-正则表达式和 re 模块应用 摘要: Python 的 re 模块提供了强大的正则表达式操作功能,用于在字符串中搜索.匹配.替换等 ...

  3. Guava中的Joiner和Splitter

    目录 Guava 介绍 Joiner list转string map转string 处理嵌套集合 处理null值 Splitter string转list string转map 多个拆分符 输出 代码 ...

  4. Ewald求和在分子静电势能计算中的应用

    技术背景 分子动力学模拟中,计算周期性边界条件的静电势常被视作计算的瓶颈之一.形式上是比较容易的,例如不考虑周期性边界条件的话,静电势能就是: \[E=\frac{1}{4\pi\epsilon_0} ...

  5. 使用nacos上传配置文件报错

    1.使用nacos导入配置文件报错:未读取到合法数据,请检查导入的数据文件. 对比在naocs server中导出的文件,发现是少了一级目录.需要创建一个文件夹,名称为组的名称.因为在nacos上传文 ...

  6. 云原生周刊:优化 Uber 的持续部署丨2024.10.14

    开源项目推荐 Cog Cog 是将机器学习模型打包到容器的工具.可通过配置将机器学习模型所需的环境和依赖,自动打包到容器里方便部署,让你不再为编写 Docker 文件和 CUDA 而痛苦,还能自动启动 ...

  7. 一文读懂 KubeSphere 企业版 4.0:多品类生态价值赋能的里程碑

    近日,青云科技 KubeSphere 团队革新先行,重磅发布了沉淀数年.倾力打造的全新分布式云原生可扩展开放架构--KubeSphere LuBan,以及在此之上构建的化整为零.全能开放.随时随地自由 ...

  8. Windows 使用 Mingw-w64 配置GCC套件

    Mingw-w64里的gcc和g++应该是很多人常用的编译工具.但是他的下载资源很乱,不好找(注意:MinGW和MinGW-w64是同宗同源的两款软件!),要么就是版本太老.SourceForge上有 ...

  9. 买游戏本玩战锤40K ?ToDesk云电脑教你2元升级旧电脑,省钱!

    <战锤40K:星际战士>终于出续作了!不得不说这款多人射击游戏的热度实在太高啦,刚发布两天就登顶Steam销量第一名. <战锤40K:星际战士2>不仅继承了前作的精髓,更在画面 ...

  10. Nuxt.js 应用中的 builder:generateApp 事件钩子详解

    title: Nuxt.js 应用中的 builder:generateApp 事件钩子详解 date: 2024/10/23 updated: 2024/10/23 author: cmdragon ...