在 Visual Studio 中使用 EditorConfig 統一程式碼風格(含原生與外掛)
EditorConfig 是一種被各種編輯器廣泛支援的配置,使用此配置有助於專案在整個團隊中保持一致的程式碼風格。Visual Studio 2017 開始原生支援 EditorConfig。
本文將介紹 Visual Studio 對 EditorConfig 的支援情況(含原生與外掛),並給出符合 .NET 和 C# 約定的 EditorConfig 詳細設定。
EditorConfig 的廣泛支援
在 EditorConfig 官網中,貼出了一些可以純原生無需任何外掛支援 EditorConfig 程式碼風格配置的編輯器:
▲ 原生支援 EditorConfig 的編輯器
然後還貼出了可以通過外掛支援的編輯器:
▲ 可以通過外掛支援 EditorConfig 的編輯器
EditorConfig 本身只定義了一個核心集,表示所有語言都共同遵循的程式碼格式規範: ofollow,noindex" target="_blank">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
- 語言特定屬性
- 所有 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 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 的支援情況可以參考: 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(); varlogger2 = (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://walterlv.com/post/editor-config-for-visual-studio.html ,以避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名 呂毅 (包含連結:https://walterlv.com ),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。如有任何疑問,請 與我聯絡 ([email protected]) 。