ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Visual Studio 新建文件自动添加注释头配置指南

Visual Studio 新建文件自动添加注释头配置指南 在 Microsoft Visual Studio 里新建一个文件就自动带上注释头这事听起来微不足道但只要团队超过两个人、或者项目要对外开源、或者公司有一份代码合规检查清单它立刻就会从小事变成每周都要吵一次的事。我见过太多仓库里同时存在五种风格的注释头有的写着三年前的同事名字有的版权年份还停在 2021还有一半文件干脆一行注释都没有。手工补注释这件事的失败率极高原因不是程序员懒而是**记得写这种依赖人的约束在每天新建十几次文件的节奏里必然崩掉**。这篇内容就是把这个约束交给工具去管在 Microsoft Visual Studio 里让新建文件自动添加注释改模板、跑命令、验证效果一条链路走完。内容会覆盖三条不同成本的路线直接改 VS 安装目录里的内置项模板、用导出模板做个人模板、以及用.editorconfig配合代码清理做兜底。三条路线的适用人群、生效时机、被 VS 更新覆盖的风险各不相同我会把它们拆开讲清楚也把踩过的坑一个个摆出来——比如模板里写一个$符号会导致生成失败、中文注释保存成不带 BOM 的 UTF-8 会乱码、改完模板不跑注册命令等于白改。看完之后你应该能在半小时内让自己或者整个团队的每个新文件都带着统一、干净、机器可读的注释头。1. 先想清楚为什么新建文件加注释值得花时间配置1.1 手工补注释的三种典型翻车现场第一种翻车是格式漂移。同一个项目里A 同事的注释头是五行B 同事是两行C 同事用的是/* */块注释D 同事把注释写在了using下面。单独看每个文件都没问题但仓库里出现五六种形态之后任何想做批量处理的工具比如统计版权年份的脚本、扫描许可证标识的合规工具都会失效。格式不统一带来的损失不是美感问题而是自动化能力的丧失。第二种翻车是信息腐烂。很多团队的文件头模板长这样创建人、创建日期、修改人、修改日期、修改说明。前两个字段还能靠模板自动填后面几个字段只能手写。结果就是半年之后文件头里写的2024-03-12 张三 修复空指针和 Git 里的真实历史完全对不上——文件被改过八次注释头还是最初那一行。我在做代码评审的时候基本上默认忽略这类变更记录注释因为它们的信息密度远低于git blame。第三种翻车是合规风险。如果代码要交付给客户、要进开源仓库、要通过法务审核缺少版权声明和许可证标识是实打实的问题。这类检查往往是事后做的等到发现的时候可能已经有几百个文件需要逐个补。与其事后补救不如在建文件的那一刻就把它钉死。1.2 Visual Studio 里能实现建文件即带注释的三条路Visual Studio 本身没有像某些 IDE 那样提供一个显眼的文件头注释模板输入框但它其实有三套机制可以做到这件事很多人只找到了其中一套然后就以为VS 不支持。第一套是项模板Item Template。你在添加新项对话框里看到的类接口枚举结构背后都是硬盘上真实存在的模板文件路径在 VS 安装目录的Common7\IDE\ItemTemplates下面。改这些模板文件里的内容新建出来的文件就带着你的注释头。生效是即时的——点确定的那一刻注释就在文件里了。第二套是代码片段Code Snippet。写一个header片段输入两个 Tab 就能把注释头插进去。它的优点是改起来最简单缺点是不自动——还是得人记得敲。第三套是基于代码样式分析器的方案。.editorconfig里有file_header_template这个属性配合 IDE0073 这个规则VS 会检查每个.cs文件有没有匹配的文件头并且提供添加文件头的修复。如果再把保存时运行代码清理打开文件第一次保存的时候注释头会被补上。它的问题也很明确不是在建文件那一刻生效而是在保存那一刻生效。1.3 三条路线的取舍一张表说清我为什么全都用方案生效时机覆盖范围被 VS 更新覆盖团队共享成本适合谁改内置项模板选中类并确定时立刻生效只覆盖你改过的那几种模板会升级/修复 VS 后可能还原高需要每人自己改一遍或写脚本个人提效、单人项目导出个人模板从我的模板入口新建时生效你自己导出的那几种不会中可以把模板目录同步小团队、个人习惯固定.editorconfig 代码清理文件第一次保存时生效全仓库所有.cs文件不会跟着仓库走低跟着 Git 走任何需要一致性的团队我自己的做法是前两条管即时体验第三条管长期兜底。理由很直接模板方案只能管住用 VS 的新建项对话框创建的文件管不住别人从别的项目复制过来的文件、管不住用命令行dotnet new生成的文件、更管不住 AI 补全帮你新建的文件。.editorconfig这套跟着仓库走谁拉下来代码谁就受约束而且可以在 CI 上校验属于真正意义上的规范。模板方案则是让大部分情况下根本不需要修两边配合起来才舒服。顺带说一个容易被忽略的事实Visual Studio 的添加新项和命令行的dotnet new用的是两套完全不同的模板系统。前者读ItemTemplates目录后者读~/.templateengine下的模板包。你改了一个另一个纹丝不动。所以如果你的团队混用 VS 图形界面和命令行建文件两边都得配。2. 摸清 ItemTemplates 目录VS 的添加新项到底在读什么2.1 从添加新项对话框反推模板的物理位置打开一个 C# 项目右键项目添加、新建项快捷键是 CtrlShiftA左侧选已安装下面的C#你会看到类接口结构枚举这一排。这些条目不是 VS 用代码硬编码画出来的而是它扫描了磁盘目录后动态生成的。扫描的根目录就是VS 安装根目录\Common7\IDE\ItemTemplates以 Visual Studio 2022 社区版装在默认位置为例完整路径是C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\ItemTemplates这里要提醒一个最新版本上的变化Visual Studio 2019 及更早版本的安装根目录带(x86)和版本年份比如C:\Program Files (x86)\Microsoft Visual Studio 14.0\从 Visual Studio 2022 开始目录结构变成了Program Files\Microsoft Visual Studio\2022\版本。路径变了但下面的Common7\IDE\ItemTemplates这一层没变所以老教程里的后半段依然可以参考。再往下走你会看到一个按语言和类别分层的结果。C# 语言对应的分支大致是ItemTemplates\CSharp\Code\语言区域代码\Class\那个语言区域代码是很多人第一次找模板时最困惑的地方。简体中文版 VS 的目录名是2052英文版是1033。如果你照着英文教程去找1033却怎么也找不到大概率是因为你的 VS 装了中文语言包模板实际躺在2052下。这两个目录可能同时存在也可能只存在一个——取决于你当初装 VS 时勾了哪些语言。进到Class文件夹里你会看到三样东西一个Class.cs、一个Class.vstemplate、一个Class.ico。Class.cs就是新文件内容的母版你在添加新项里预览到的代码就是它Class.vstemplate是这个模板的元数据Class.ico是对话框里那个小图标。2.2 .vstemplate 管元数据源文件管正文别改错文件很多人第一次动手会去改.vstemplate因为它的名字看起来更像配置。这是个方向性错误。注释头要写进Class.cs因为那才是新文件内容的母版。.vstemplate里放的是元数据用来告诉 VS我叫什么名字图标长什么样属于哪个语言新建时的默认文件名是什么。一个简化过的.vstemplate长这样VSTemplate Version3.0.0 TypeItem xmlnshttp://schemas.microsoft.com/developer/vstemplate/2005 TemplateData DefaultNameClass.cs/DefaultName Name类/Name Description一个空的类定义/Description ProjectTypeCSharp/ProjectType SortOrder10/SortOrder IconClass.ico/Icon TemplateIDMicrosoft.CSharp.Class/TemplateID /TemplateData TemplateContent References / ProjectItem SubTypeCode TargetFileName$fileinputname$.cs ReplaceParameterstrueClass.cs/ProjectItem /TemplateContent /VSTemplate这里面有几个字段属于身份证级别的没事不要动DefaultName决定了新建对话框里默认填的文件名改了会让新建流程变得别扭ProjectType决定了这个模板出现在哪类项目下改了可能整个条目直接消失TemplateID是 VS 用来识别这个内置项的标识动它的风险最高。相比之下Name和Description只是显示用的文字想改随便改比如把描述改成一个空的类定义含团队注释头方便团队里其他人一眼看出这个模板被定制过。TargetFileName$fileinputname$.cs这一行的意思是新建出来的文件名跟你输入的名字一致。ReplaceParameterstrue非常关键它声明了这个模板文件里的$xxx$占位符需要被替换。如果你把它改成false那你写的$rootnamespace$会原样留在生成的文件里看起来像一堆乱码。改模板的时候顺手确认这一行还是true。2.3 模板参数表哪些占位符能用哪些只是看起来能用模板里的$xxx$叫模板参数VS 会在生成文件时把它们替换成实际值。常用的那些我整理在下面但先说一句实在话不同 VS 版本、不同类型模板支持的参数集合不完全一致网上抄来的参数在你这台机器上报错是常有的事。所以正确姿势是先小范围验证——改完一个模板新建一个文件看结果别一次性改五个模板然后一起排错。参数含义实用建议$rootnamespace$项目的根命名空间最常用但注意它跟文件夹结构无关$safeitemrootname$经处理后的文件名非法字符被替换类名一律用它别用$itemname$$fileinputname$用户在对话框里输入的文件名只适合放在文件名位置$year$当前年份版权年份首选不受区域设置影响$time$当前日期时间格式受系统区域设置影响慎用于团队规范$username$当前登录用户名不建议写进注释头人一换就腐烂$guid1$到$guid10$生成新的 GUID少数场景有用注释头里基本用不上关于$safeitemrootname$和$itemname$的区别值得单独说一句。假设用户输入的文件名是订单-处理器.cs直接用$itemname$拼出来的类名里会带着连字符编译器当场报错$safeitemrootname$会把不合法字符处理掉生成一个能编译的标识符。模板里凡是拼类名、接口名、结构名的地方一律用$safeitemrootname$。还有一个真实存在的坑$time$的输出格式跟着操作系统的区域设置走。同一个模板中文环境下生成的是2024/5/20 14:32:11英文环境下可能是5/20/2024 2:32:11 PM。一个跨国协作的团队如果模板里用了$time$仓库里就会出现两种日期格式的文件头。如果注释头里非要带时间用$year$就够了需要精确到天的靠 Git 记录不要靠注释。3. 动手改内置类模板把注释头写进 Class.cs3.1 动手前的三件准备备份、管理员权限、先关 VS在动手之前先把这三件事做完能省掉后面百分之八十的麻烦。第一件备份。把整个Class文件夹复制一份到处名字就叫Class.bak。这不是过度谨慎——后面跑注册命令之后如果生成结果不对你需要在两分钟内退回原状而不是靠记忆回想自己删了哪一行。备份要连同三类文件一起.cs、.vstemplate、.ico。更稳的做法是把原始目录整棵树压缩成一个 zip 放到项目之外的盘里因为 VS 的修复操作也可能动到这些文件。第二件用管理员权限开编辑器。C:\Program Files\Microsoft Visual Studio\...这个位置默认不允许普通权限写入。很多人改完保存编辑器弹出拒绝访问然后以为自己改的是另一个文件。正确做法是右键你的文本编辑器记事本、VS Code、Notepad 都行选择以管理员身份运行再从编辑器里打开模板文件。用 Visual Studio 自己来编辑这些文件也可以但同样要以管理员身份启动而且改完得关掉 VS 才能跑注册命令——这一点很容易忘。第三件关掉所有 Visual Studio 实例。注册命令要在 VS 进程完全退出后执行否则有的文件被占用注册会静默失败。任务栏里那个窗口关了不代表进程没了任务管理器里确认一下devenv.exe已经全部结束。另外如果你开着多个 VS 版本比如 2019 和 2022 并存注意确认你要改的是哪一个版本的目录跑命令的时候也要跑对应版本的devenv.exe。3.2 注释头怎么写一个可以直接抄的模板下面这份Class.cs是我现在用的版本你可以直接抄把公司名和许可证标识换掉// SPDX-FileCopyrightText: 2024 你的团队或公司名 // SPDX-License-Identifier: MIT // // 文件用途$safeitemrootname$ 的职责说明写在这里 // 创建年份$year$ // // 约定本文件的公开类型不要随意改名外部可能通过反射引用 using System; using System.Collections.Generic; namespace $rootnamespace$ { /// summary /// $safeitemrootname$ 的说明。 /// /summary public class $safeitemrootname$ { } }关于这份模板有几个设计决定值得解释。为什么用 SPDX 标识符而不是自己发明一行版权所有。SPDX 是一套标准化的许可证表达方式SPDX-FileCopyrightText和SPDX-License-Identifier是两个固定前缀主流的合规扫描工具能直接解析它们。自己写的Copyright (c) 2024 XXX保留所有权利看起来更正式但机器读起来要靠正则去猜。既然注释头的一个主要目的就是让机器能读那就用机器认得的写法。为什么没有作者和修改记录字段。前面说过这两个字段是腐烂重灾区。真要看谁在什么时候改了哪一行git blame一秒给出答案而且永远不会过时。注释头只留那些 Git 里没有的信息文件用途、许可证、以及为什么这个文件这么写的约定。为什么用$year$而不是完整时间。除了前面说的区域设置问题还有一个很实际的原因完整时间戳会让同一批新建的文件头部看起来各不相同做 grep 统计的时候很难写出一致的匹配规则。年份足够满足版权声明的需求。为什么using只留了两行。老版本 VS 的类模板里有一段$if$ ($targetframeworkversion$ 3.5) ... $endif$之类的条件块用来按目标框架版本决定要不要引System.Linq。现在大部分项目都是 SDK 风格目标框架早就远超那些分界线留着只会让每个新文件顶着一堆用不到的using然后被移除未使用的 using清理掉。我直接把条件块删了——如果你改的模板里有$if$、$else$、$endif$这组指令删掉它们不会报错但会丢失条件逻辑所以删之前先想清楚是不是真的不需要。这里有个必须强调的坑模板里的$是特殊字符。如果你在注释里写了$开头的符号比如正则表达式$1、价格符号、或者某些生成工具用的$Id$标记VS 会尝试把它当成模板参数解析轻则原样保留重则抛出参数异常导致新建失败。要输出一个字面量的美元符号写成两个$$。这个细节在文档里往往一笔带过但实际踩到的人非常多而且报错信息通常不告诉你问题在哪个字符上。另一个坑是编码。模板文件里的中文注释如果保存成UTF-8 无 BOM在某些 VS 版本上生成出来的文件会出现中文乱码。稳妥的做法是把模板文件保存为UTF-8 with BOM或者干脆避免在注释头里写中文。我个人的选择是注释头里只写英文的 SPDX 行中文说明放在summary里——因为summary是开发时经常看的注释头是给工具看的。3.3 让 VS 重新读模板两条命令的区别改完文件直接打开 VS你会发现新建的类里什么变化都没有。这不是改错了而是VS 在启动时已经把模板信息缓存到了内存和本地的元数据存储里它不会定期去扫硬盘。你需要主动让它重新注册。具体命令有两个区别在于# 注册项目模板和项模板 devenv.exe /installvstemplates # 更新 VS 的配置缓存2017 及以后版本更常用 devenv.exe /updateconfigurationdevenv.exe的完整路径在 VS 安装目录的Common7\IDE\下面。以 2022 社区版为例C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe最省事的执行方式是打开开始菜单里随 VS 一起装的Developer Command Prompt开发者命令提示符它已经把这个目录加到 PATH 里了直接敲devenv /installvstemplates就行。如果用的是普通命令提示符就得敲完整路径注意路径里有空格要用引号包起来而且这个操作需要管理员权限的窗口。我的习惯是两条都跑一遍顺序无所谓跑完重启 VS。老教程里只提/installvstemplates较新的版本上单跑它有时候不够加上/updateconfiguration更稳。如果你的 VS 语言包目录是2052而你在1033下也改了东西两条命令同样会把两边都重新扫一遍不用分别执行。命令执行的时候可能几秒钟没有任何输出这是正常的——它不是那种会打印成功的程序。判断成功的标准是新建一个类看看有没有注释头。3.4 验证与改了不生效的排查顺序验证很简单打开一个 C# 项目右键、添加、新建项、类随便输个名字确定看新文件顶部有没有你的注释头。如果没生效按下面这个顺序排查我按实际踩到的概率从高到低排改错了版本或语言目录。你机器上可能同时装了 2019 和 2022或者同时存在1033和2052而你改的那个不是你正在用的那个。确认方式在添加新项对话框里看一眼默认文件名旁边的图标或者干脆把两个目录都改一遍。没跑注册命令或者跑命令时 VS 还开着。这是第二大原因。任务管理器里确认devenv.exe全部退出再跑命令。改错了文件。注释头必须写在Class.cs里不是.vstemplate里。有的人把注释写在.vstemplate的Description里然后发现只是对话框里的描述变了。.cs文件里把$写坏了。检查有没有单独的$、有没有不成对的$或者$if$系列指令被删了一半。文件被 VS 还原了。如果你在改模板期间或之后跑过 VS 的修复操作、装过大版本更新安装目录里的文件会被重置。这就是为什么前面强调要备份。还有一个容易误判的情况你新建的不是类而是接口或者枚举。每个类型的模板是独立的文件夹只改Class只影响类。这一点其实是个好消息——你可以给接口单独写一套注释头把summary的措辞换成接口专用的说法。4. 不动安装目录的方案导出模板与用户模板目录4.1 用导出模板向导做一个属于你自己的类模板改Program Files最大的问题是两件事需要管理员权限以及VS 每次大版本升级或者执行修复之后都可能把它覆盖掉。如果你不想反复折腾第二条路线更省心。Visual Studio 自带一个导出模板向导入口在菜单的项目、导出模板里。向导会问你导出的范围项目模板还是项模板选项模板然后在列表里勾一个类型比如类一路下一步。这里的巧妙之处在于向导导出的不是你选的那个类型的原始模板而是当前解决方案里那个文件的实际内容。所以正确的用法是——先在你的项目里新建一个类把注释头写好、using精简好、summary补好然后拿这个已经调教过的文件去导出。导出的成品会包含注释头因为它复制的是真实文件内容。向导最后会问你模板名、模板说明和图标然后输出一个.zip文件。这个 zip 会被放进用户模板目录同时在添加新项对话框里多出一个以你的项目名命名的分类。4.2 用户模板目录位置、入口和为什么我更推荐这条路导出模板默认落在这个位置以 VS 2022 为例2019 及更早版本把年份和版本名替换一下即可%USERPROFILE%\Documents\Visual Studio 2022\Templates\ItemTemplates也可以直接手动往这个目录里放 zip。zip 里面的结构和安装目录里的模板结构一样一个.cs带你的注释头、一个.vstemplate、一个图标.vstemplate里的TemplateID换成你自己的唯一字符串就行。往这个目录放东西不需要管理员权限也不受影响于 VS 的修复和升级。它在添加新项对话框里的入口位置比较绕左侧选已安装往下滚通常会看到以你项目名或模板分类命名的节点有些人需要在对话框里勾上显示所有模板之类的选项才能看到。不同版本的表现略有差异第一次找不到的时候别急着怀疑人生把左侧的树展开全看一遍。为什么我更推荐这条路作为主力方案三个理由。不影响 VS 本身的完整性哪天不想要了把 zip 删了就回到原样不留尾巴。可以跟着自己走把ItemTemplates目录同步到网盘或者放进 dotfiles 仓库换电脑的时候一复制就完事。能一次性做出多个定制类型类、接口、记录类型各做一个比逐个去改安装目录快得多。它的短板也要说清楚入口不如内置模板顺手新同事不会自己去找我的模板所以团队推广时还是得配一份说明。另外它只覆盖用这个模板新建的场景别人从别的项目复制文件过来它管不着。4.3 团队共享的三条路VSIX、仓库里的配置文件、命令行模板包如果是团队场景让每个人自己动手改本机目录是不现实的——总有几个人的路径不一样、语言包不一样、VS 版本不一样最后做出来的东西五花八门。共享有三条相对可靠的路。第一条是 VSIX 扩展。把模板打成一个 VSIX 包团队成员从内部分发渠道装一下就行。这条路的成本在于要搭一个扩展项目、处理版本号和签名适合规范要求比较硬、人数比较多的团队。好处是它走的是 VS 扩展机制不会被修复操作干掉卸载也干净。第二条是把规范放进仓库。也就是下一节要讲的.editorconfig方案。它不需要安装任何东西跟着代码走新同事拉下代码就自动受约束还能在 CI 上卡住。这是我给大多数团队的首选建议。第三条是dotnet new的自定义模板包。如果你团队里有人习惯命令行建文件可以做一套模板包用dotnet new install装到本机。这套模板的元数据文件叫template.json跟.vstemplate是两套完全不同的东西别混着抄。它的好处是能同时服务命令行和部分 IDE 场景还能通过包管理的方式分发版本。5. .editorconfig 文件头规则 保存时清理不能即时但能兜底5.1 为什么这套机制不是在建文件那一刻生效.editorconfig里的文件头规则本质上是代码样式分析器的一条规则。分析器的运行时机是文件被加载、被编辑、被保存而不是文件被创建。所以它天生做不到点下去就有注释。但这恰恰是它的价值所在它覆盖的是所有.cs文件不管这些文件是怎么来的。从模板建的、从别的项目复制过来的、命令行生成的、同事发给你粘贴进来的——只要文件在项目里这条规则就会盯上它。模板方案解决的是大部分情况不用管这套方案解决的是漏网的全部捞回来两者的分工很清楚。还有一层价值是可校验。规则写在.editorconfig里跟着 Git 走可以在 CI 上跑一遍检查谁提交了没有文件头的文件就构建失败。这种事靠人盯是盯不住的靠工具两行命令就搞定。5.2 具体配置一个能直接用的 .editorconfig把下面这份文件放在解决方案根目录或者仓库根目录看你想覆盖的范围文件名就是.editorconfig注意前面有个点没有后缀root true [*.cs] # 文件头模板支持 {fileName} 和 {projectName} 两个占位符 # 换行用 \n 表示 file_header_template SPDX-FileCopyrightText: 2024 你的团队名\nSPDX-License-Identifier: MIT\n\n文件用途{fileName} # 把这条规则从背景提示提到会亮警告 dotnet_diagnostic.IDE0073.severity warning # 顺便把命名空间和 using 的顺序管一管 dotnet_sort_system_directives_first true几个要点解释一下。root true声明这是最顶层配置文件分析器不会再往上找避免被用户目录下的同名文件干扰。[*.cs]表示下面的配置只对 C# 文件生效——如果你的项目里还有.xaml、.razor、.py那要各自开一节而且它们的注释语法完全不同XAML 用!-- --Razor 用* *Python 用#。file_header_template的值里\n会被解释成换行。可用的占位符是{fileName}和{projectName}具体的支持范围跟 IDE 版本和 SDK 版本有关写完一定要拿一个测试文件跑一次看生成出来的首行有没有多余的空白、换行位置对不对。别写完就直接推到主分支。IDE0073是这条规则在分析器里的编号全称大意是要求文件头。把它设成warning文件在编辑器里就会有个波浪线Ctrl.能调出添加文件头的快速修复。如果你只想要提示不想要黄线可以设成suggestion如果想让它在构建时直接失败设成error。5.3 打开保存时清理让注释头在第一
返回列表