当前位置: 首页 > news >正文

在 Visual Studio 中使用 EditorConfig 统一代码风格(含原生与插件)

EditorConfig 是一种被各种编辑器广泛支持的配置,使用此配置有助于项目在整个团队中保持一致的代码风格。Visual Studio 2017 开始原生支持 EditorConfig。

本文将介绍 Visual Studio 对 EditorConfig 的支持情况(含原生与插件),并给出符合 .NET 和 C# 约定的 EditorConfig 详细设置。


本文内容

    • EditorConfig 的广泛支持
    • Visual Studio 对 EditorConfig 的支持程度
    • 在 Visual Studio 中添加 EditorConfig 配置
    • 在 Visual Studio 中开启 EditorConfig 支持
    • 在 ReSharper 中开启 EditorConfig 支持
    • 效果体验
      • 附 EditorConfig Language Service 生成的属性集
      • 附 IntelliCode 生成的属性集

EditorConfig 的广泛支持

在 EditorConfig 官网中,贴出了一些可以纯原生无需任何插件支持 EditorConfig 代码风格配置的编辑器:

原生支持 EditorConfig 的编辑器
▲ 原生支持 EditorConfig 的编辑器

然后还贴出了可以通过插件支持的编辑器:

在这里插入图片描述
▲ 可以通过插件支持 EditorConfig 的编辑器

EditorConfig 本身只定义了一个核心集,表示所有语言都共同遵循的代码格式规范:EditorConfig 属性的核心集。同时,还有一些其他定义的规范:EditorConfig 的完整属性,不过这里不包括语言特定的规范。

Visual Studio 对 EditorConfig 的支持程度

Visual Studio 2017 开始添加了对 EditorConfig 的原生支持(你当然能在上面看到 Visual Studio 的图标啦)。

原生的 Visual Studio 2017 支持 EditorConfig 属性的核心集和一些语言的特定属性。具体来说,是这一些:

  • 核心属性
    • indent_style
    • indent_size
    • tab_width
    • end_of_line
    • charset
    • trim_trailing_whitespace
    • insert_final_newline
    • root
  • 语言特定属性
    • 所有 Visual Studio 支持的语言(XML 除外)均支持 EditorConfig 编辑器设置。
    • 此外,EditorConfig 还支持适用于 C# 和 Visual Basic 的代码样式约定和命名约定。

也就是说,当你的项目中存在 EditorConfig 的配置文件 .editorconfig 的时候,Visual Studio 就会应用 EditorConfig 的设置,而且可以适用于多数情况下的编程约定。

Visual Studio 中 .NET 相关语言(C# VB)的 EditorConfig 属性,可以参考 .NET coding convention settings For EditorConfig。

在 Visual Studio 中添加 EditorConfig 配置

Visual Studio 支持 EditorConfig 对编程规范的约束。对于多数开发者来说,不需要安装任何插件的情况下这个编程规范的约束就会生效。

不过,还是需要有一些小伙伴进行编程规范的设置。设置规范可以使用很多个插件,比如 EditorConfig Language Service 和 Visual Studio IntelliCode。当然,前者会更加专业,后者只是因为需要使用到 EditorConfig 的配置,顺便带上了 EditorConfig 的编辑体验。

安装了 EditorConfig Language Service 插件之后,在解决方案上右键,添加 .editorconfig 文件。

添加 .editorconfig 文件
▲ 添加 .editorconfig 文件

当然,也许你会发现在我的图中,两个插件都能生成 .editorconfig 文件。EditorConfig Language Service 生成的 .editorconfig 文件是空的,而 IntelliCode 一经添加便提供了丰富的 C# 语言约定的属性设置。不过,IntelliCode 提供的设置多少取决于你目前解决方案中的项目类型,这些属性是从 这里 推断的。

如果你使用 EditorConfig Language Service 生成了 .editorconfig 文件,则可以继续点击小灯泡生成按照微软约定的编程规范:

生成规范
▲ 生成规范

在 Visual Studio 中开启 EditorConfig 支持

实际上,Visual Studio 一旦检测到 .editorconfig 文件的存在,格式约定就会自动生效。

在 ReSharper 中开启 EditorConfig 支持

一样的,ReSharper 默认是开启了 EditorConfig 配置的检测的,也就是说只要存在 .editorconfig 文件,那么 EditorConfig 也会在 ReSharper 的格式化中生效。

ReSharper 中的 EditorConfig 配置支持

ReSharper 对于 EditorConfig 的支持情况可以参考:Using EditorConfig - Help - ReSharper。

效果体验

我们来看一段风格十分混乱不忍直视的代码:

using System;
using System.Threading.Tasks;

namespace Walterlv.Demo
{
    public static class Program
    {
        [STAThread]
        private static int Main(string[] args)
        {
            var logger = (ILogger)   new Logger();
            var   logger2 = (ILogger)new Logger();
            var managerTask = Task.Run(  () => 
                {
                    var manager = new Manager(logger);
                    manager.Run();
                    return manager;
                });
            var app = new App(managerTask) {

            };
                app.InitializeComponent();
                app.Run();
                return 0;
        }
    }
}

无论你是使用什么方式,最终都能格式化成下面这样:

  • 你可以直接输入,在遇到 }; 的时候就会格式化
  • 你可以 Ctrl+V 粘贴,粘贴后直接就是格式化后的代码
  • 你可以按下 Ctrl+Alt+Enter(ReSharper),这样整份文档就会格式化
  • 你可以按下 Ctrl+K, D(Visual Studio 的 Cleanup),这样也能格式化
using System;
using System.Threading.Tasks;

namespace Walterlv.Demo
{
    public static class Program
    {
        [STAThread]
        private static int Main(string[] args)
        {
            var logger = (ILogger)new Logger();
            var logger2 = (ILogger)new Logger();
            var managerTask = Task.Run(() =>
            {
                var manager = new Manager(logger);
                manager.Run();
                return manager;
            });
            var app = new App(managerTask)
            {

            };
            app.InitializeComponent();
            app.Run();
            return 0;
        }
    }
}

附 EditorConfig Language Service 生成的属性集

[*]
end_of_line = crlf
charset = utf-8-bom
indent_size = 4
insert_final_newline = true
tab_width = 4
trim_trailing_whitespace = true

[*.xml]
indent_style = space

[*.{cs,vb}]
dotnet_sort_system_directives_first = true
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_object_initializer = true:suggestion
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true
dotnet_style_prefer_conditional_expression_over_return = true
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_qualification_for_event = false:silent
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_readonly_field = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent

[*.cs]
csharp_indent_case_contents = true
csharp_indent_labels = flush_left
csharp_indent_switch_labels = true
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
csharp_prefer_braces = true:silent
csharp_prefer_simple_default_expression = true:suggestion
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_around_binary_operators = before_and_after
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_style_conditional_delegate_call = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_var_elsewhere = true:silent
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent

[*.vb]
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion:suggestion

附 IntelliCode 生成的属性集

# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\Users\lvyi\Walterlv.Demo codebase based on best match to current usage at 2018/11/20
# You can modify the rules from these initially generated values to suit your own policies
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
[*.cs]

#Core editorconfig formatting - indentation

#use soft tabs (spaces) for indentation
indent_style = space

#Formatting - indentation options

#indent switch case contents.
csharp_indent_case_contents = true
#csharp_indent_case_contents_when_block
csharp_indent_case_contents_when_block = false
#indent switch labels
csharp_indent_switch_labels = true

#Formatting - new line options

#place catch statements on a new line
csharp_new_line_before_catch = true
#place else statements on a new line
csharp_new_line_before_else = true
#require finally statements to be on a new line after the closing brace
csharp_new_line_before_finally = true
#require braces to be on a new line for methods, accessors, control_blocks, lambdas, properties, and types (also known as "Allman" style)
csharp_new_line_before_open_brace = methods, accessors, control_blocks, lambdas, properties, types

#Formatting - organize using options

#sort System.* using directives alphabetically, and place them before other usings
dotnet_sort_system_directives_first = true

#Formatting - spacing options

#require a space before the colon for bases or interfaces in a type declaration
csharp_space_after_colon_in_inheritance_clause = true
#require a space after a keyword in a control flow statement such as a for loop
csharp_space_after_keywords_in_control_flow_statements = true
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_before_colon_in_inheritance_clause = true
#remove space within empty argument list parentheses
csharp_space_between_method_call_empty_parameter_list_parentheses = false
#remove space between method call name and opening parenthesis
csharp_space_between_method_call_name_and_opening_parenthesis = false
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
csharp_space_between_method_call_parameter_list_parentheses = false
#remove space within empty parameter list parentheses for a method declaration
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
csharp_space_between_method_declaration_parameter_list_parentheses = false

#Formatting - wrapping options

#leave code block on single line
csharp_preserve_single_line_blocks = true
#leave statements and member declarations on the same line
csharp_preserve_single_line_statements = true

#Style - expression bodied member options

#prefer block bodies for accessors
csharp_style_expression_bodied_accessors = false:suggestion
#prefer block bodies for constructors
csharp_style_expression_bodied_constructors = false:suggestion
#prefer block bodies for indexers
csharp_style_expression_bodied_indexers = false:suggestion
#prefer block bodies for methods
csharp_style_expression_bodied_methods = false:suggestion
#prefer block bodies for properties
csharp_style_expression_bodied_properties = false:suggestion

#Style - expression level options

#prefer out variables to be declared before the method call
csharp_style_inlined_variable_declaration = false:suggestion
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_member_access = true:suggestion

#Style - implicit and explicit types

#prefer var is used to declare variables with built-in system types such as int
csharp_style_var_for_built_in_types = true:suggestion
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
csharp_style_var_when_type_is_apparent = true:suggestion

#Style - language keyword and framework type options

#prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion

#Style - qualification options

#prefer events not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_event = false:suggestion
#prefer fields not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_field = false:suggestion
#prefer methods not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_method = false:suggestion
#prefer properties not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_property = false:suggestion

参考资料

  • Using EditorConfig settings in Visual Studio - Visual Studio - Microsoft Docs
  • .NET coding convention settings For EditorConfig - Visual Studio - Microsoft Docs

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 在 Visual Studio Code 中添加自定义的代码片段
  • 用 dotTrace 进行性能分析时,Timeline 打不开?无法启动进程?也许你需要先开启系统性能计数器的访问权限
  • 了解 .NET/C# 程序集的加载时机,以便优化程序启动性能
  • git 如何更可靠地解决冲突?
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • 文件被占用?系统自带的“资源监视器(resmon)”也能帮你找到占用它的真凶
  • Windows 系统文件资源管理器的命令行参数(如何降权打开程序,如何选择文件)
  • 为 .NET 各种开发工具设置网络代理,提升在大陆的网络性能
  • 如何在旧版本的 .NET Core / Framework 中使用 C# 8 的异步流(IAsyncDisposable / IAsyncEnumerable / IAsyncEnumerator)
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • 为什么实现 .NET 的 ICollection 集合时需要实现 SyncRoot 属性?如何正确实现这个属性?
  • 为什么不应该公开用来同步的加锁对象?为什么不应该 lock(this)/lock(string) 或者 lock 任何非私有对象?
  • WPF 中如何创建忽略 DPI 属性的图片
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • Win32 方法 CreateFile 中选择合适的文件打开模式(CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING, OPEN_ALWAYS, TRUNCATE_EXI
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • Android Studio:GIT提交项目到远程仓库
  • java8-模拟hadoop
  • Javascript Math对象和Date对象常用方法详解
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • 反思总结然后整装待发
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 入手阿里云新服务器的部署NODE
  • 设计模式走一遍---观察者模式
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 一些css基础学习笔记
  • ionic异常记录
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 第二十章:异步和文件I/O.(二十三)
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • #1015 : KMP算法
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • (175)FPGA门控时钟技术
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (一)Linux+Windows下安装ffmpeg
  • (转)程序员疫苗:代码注入
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .net网站发布-允许更新此预编译站点
  • .NET性能优化(文摘)
  • /etc/sudoer文件配置简析
  • [].shift.call( arguments ) 和 [].slice.call( arguments )
  • [<死锁专题>]
  • [ACM] hdu 1201 18岁生日
  • [Android]RecyclerView添加HeaderView出现宽度问题
  • [C/C++]数据结构 堆的详解
  • [Geek Challenge 2023] web题解
  • [github全教程]github版本控制最全教学------- 大厂找工作面试必备!
  • [halcon案例2] 足球场的提取和射影变换