簡單紀錄重新格式化代碼、代碼清理的使用及設定方法
為了要讓團隊成員在撰寫代碼的時候有統一的格式,讓其他成員能夠迅速的瞭解程式碼,不因為個人風格的喜好而影響,通常我們會定義程式碼撰寫風格來讓團隊成員遵守,這個東西大概就是團隊成員一同遵守的Coding Style,像是EditorConfig或是大名鼎鼎的ESLint等等工具,其實都是在定義一系列的規則,輔助團隊透過各種支援的 IDE 達成程式碼風格的一致性
Rider 所提供的 Reformat Code 功能則是可以依據自行定義好的規則進行自動格式化,當然這些規則需要自己去設定裡面先定義好各種語言的 Code Style
設定的細節非常的多,尤其是 csharp, 就不一一截圖了,一般使用者應該也是跟我一樣直接使用預設值,然後針對結果再去做微調的動作
而呼叫使用的方式,則可以從 keymap 裡面去搜尋然後自行設定熱鍵
可以看見有三個執行的方式
reformat code#
這個方式就只是最簡單的幫你把代碼重新格式化排版而已
reformat and Cleanup#
採用這個方式的話他會再跳出視窗詢問你要套用哪一套規則來做 CleanUp 的動作
當然在檔案總管的部分也可以透過右鍵找到 reformat and cleanup的選項,一樣可以跳出視窗,如果規則都設定完成的話,可以一次將專案所有程式碼都先作一次 cleanup 然後 Commit,之後的開發 commit 內容應該也會比較乾淨些,更容易看到 Diff 的差異
silent reformat and cleanup#
跟上面一個一樣,只是會需要你先指定一份設定檔,就不會再跳出視窗詢問了
設定的方式在 Editor->Code Cleanup
上面的三個是預設的,沒有辦法修改,如果需要自訂,則必須要透過新增,或複製現有的設定出來再自行調整,指定 silent 的預設,可以從上方的 ICON 來指定預設使用哪一份 cleanup 的設定,調整細節就透過右邊的 checkbox
引入團隊#
如果想要將統一的風格推給團隊,我目前的首選還是透過EditorConfig來做這件事情,先把規則設定完畢,然後將.editorConfig commit 進去,然後再請團隊成員依據他們慣用的編輯器來將 EditorConfig 的環境準備好
支援的編輯器可以在EditorConfig 官網下方看到,以VSCode為例,需要安裝EditorConfig for VS Code這套件,但其實還需要本機安裝EditorConfig JavaScript Core才行
Rider 可以將設定資料匯出,應該有點用
我的使用習慣#
實務上我用到 cleanup 的機會其實不多,使用預設的 Reformat Code 來做格式化,因為預設的就蠻符合我要的,不變動太多程式碼,然後將縮排弄好,然後在自己新開發的程式碼檔案,在 Commit 之前才會作一次 cleanup,但如果是在前端 vue.js SFC 的部分,就會蠻常使用的。
因為我覺得他 Vue.js cleanup 的效果還不錯,尤其是亂亂的 HTML 屬性夾雜 vue 語法,有個統一的格式在習慣之後,維護起來也很方便,調整 Import 的順序也很不錯。
這些都有微調的空間,如果還想深究的話,官方文件及動手嘗試是好辦法。
補充 FileLayout.xml#
Editor->Code Style->C#->File Layout

在組織程式直線碼的部分可以透過設定 FileLayout.xml 來處理,直接參考人家寫好的範例再自行微調會比較簡單,雖然在 Resharper 裡面有 GUI 可以設定,然後再將 XML 搬來 Rider 使用也行,但直接看 XML 應該也可以理解,尤其是範例寫得還蠻清楚,照著跑一次比對一下結果應該也能理解。所以沒有很推 GUI 的設定介面。
修改完畢 XML 之後執行 Silent Reformat and Cleanup 就可以看到結果了。
<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
<TypePattern DisplayName="Non-reorderable types">
<TypePattern.Match>
<Or>
<And>
<Kind Is="Interface" />
<Or>
<HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
<HasAttribute Name="System.Runtime.InteropServices.ComImport" />
</Or>
</And>
<Kind Is="Struct" />
<HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" />
<HasAttribute Name="JetBrains.Annotations.NoReorder" />
</Or>
</TypePattern.Match>
</TypePattern>
<TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All">
<TypePattern.Match>
<And>
<Kind Is="Class" />
<HasMember>
<And>
<Kind Is="Method" />
<HasAttribute Name="Xunit.FactAttribute" Inherited="True" />
<HasAttribute Name="Xunit.TheoryAttribute" Inherited="True" />
</And>
</HasMember>
</And>
</TypePattern.Match>
<Region Name="Setup/Teardown">
<Entry DisplayName="Setup/Teardown Methods">
<Entry.Match>
<Or>
<Kind Is="Constructor" />
<And>
<Kind Is="Method" />
<ImplementsInterface Name="System.IDisposable" />
</And>
</Or>
</Entry.Match>
<Entry.SortBy>
<Kind>
<Kind.Order>
<DeclarationKind>Constructor</DeclarationKind>
</Kind.Order>
</Kind>
</Entry.SortBy>
</Entry>
</Region>
<Entry DisplayName="All other members" />
<Entry DisplayName="Test Methods" Priority="100">
<Entry.Match>
<And>
<Kind Is="Method" />
<Or>
<HasAttribute Name="Xunit.FactAttribute" Inherited="false" />
<HasAttribute Name="Xunit.TheoryAttribute" Inherited="false" />
</Or>
</And>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
</TypePattern>
<TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
<TypePattern.Match>
<And>
<Kind Is="Class" />
<Or>
<HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="true" />
<HasAttribute Name="NUnit.Framework.TestFixtureSourceAttribute" Inherited="true" />
<HasMember>
<And>
<Kind Is="Method" />
<HasAttribute Name="NUnit.Framework.TestAttribute" Inherited="false" />
<HasAttribute Name="NUnit.Framework.TestCaseAttribute" Inherited="false" />
<HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" Inherited="false" />
</And>
</HasMember>
</Or>
</And>
</TypePattern.Match>
<Region Name="Setup/Teardown">
<Entry DisplayName="Setup/Teardown Methods">
<Entry.Match>
<And>
<Kind Is="Method" />
<Or>
<HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="true" />
<HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="true" />
<HasAttribute Name="NUnit.Framework.TestFixtureSetUpAttribute" Inherited="true" />
<HasAttribute Name="NUnit.Framework.TestFixtureTearDownAttribute" Inherited="true" />
<HasAttribute Name="NUnit.Framework.OneTimeSetUpAttribute" Inherited="true" />
<HasAttribute Name="NUnit.Framework.OneTimeTearDownAttribute" Inherited="true" />
</Or>
</And>
</Entry.Match>
</Entry>
</Region>
<Entry DisplayName="All other members" />
<Entry DisplayName="Test Methods" Priority="100">
<Entry.Match>
<And>
<Kind Is="Method" />
<Or>
<HasAttribute Name="NUnit.Framework.TestAttribute" Inherited="false" />
<HasAttribute Name="NUnit.Framework.TestCaseAttribute" Inherited="false" />
<HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" Inherited="false" />
</Or>
</And>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
</TypePattern>
<TypePattern DisplayName="MSTest Test Classes" RemoveRegions="All">
<TypePattern.Match>
<And>
<Kind Is="Class" />
<Or>
<HasAttribute Name="Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute" Inherited="true" />
<HasMember>
<And>
<Kind Is="Method" />
<HasAttribute Name="Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute" Inherited="false" />
<HasAttribute Name="Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute" Inherited="false" />
</And>
</HasMember>
</Or>
</And>
</TypePattern.Match>
<Region Name="Setup/Teardown">
<Entry DisplayName="Setup/Teardown Methods">
<Entry.Match>
<And>
<Kind Is="Method" />
<Or>
<HasAttribute Name="Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute" Inherited="false" />
</Or>
</And>
</Entry.Match>
</Entry>
</Region>
<Entry DisplayName="All other members" />
<Entry DisplayName="Test Methods" Priority="100">
<Entry.Match>
<And>
<Kind Is="Method" />
<Or>
<HasAttribute Name="Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute" Inherited="false" />
</Or>
</And>
</Entry.Match>
<Entry.SortBy>
<Name />
</Entry.SortBy>
</Entry>
</TypePattern>
<TypePattern DisplayName="Default Pattern">
<Region Name="PUBLIC CONSTANTS">
<Entry DisplayName="Public Constants">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Constant" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="PUBLIC READONLY FIELDS">
<Entry DisplayName="Public Readonly Fields">
<Entry.Match>
<And>
<Access Is="Public" />
<Readonly />
<Kind Is="Field" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="PUBLIC STATIC FIELDS">
<Entry DisplayName="Public Static Fields">
<Entry.Match>
<And>
<Access Is="Public" />
<Static />
<Kind Is="Field" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="PUBLIC FIELDS">
<Entry DisplayName="Public Fields">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Field" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="CONSTANTS">
<Entry DisplayName="Constants">
<Entry.Match>
<Kind Is="Constant" />
</Entry.Match>
</Entry>
</Region>
<Region Name="READONLY FIELDS">
<Entry DisplayName="Readonly Fields">
<Entry.Match>
<And>
<Readonly />
<Kind Is="Field" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="STATIC FIELDS">
<Entry DisplayName="Static Fields">
<Entry.Match>
<And>
<Static />
<Kind Is="Field" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="FIELDS">
<Entry DisplayName="Fields">
<Entry.Match>
<And>
<Kind Is="Field" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="PUBLIC ENUMS">
<Entry DisplayName="Public Enums" Priority="100">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Enum" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="ENUMS">
<Entry DisplayName="Enums" Priority="100">
<Entry.Match>
<Kind Is="Enum" />
</Entry.Match>
</Entry>
</Region>
<Region Name="PUBLIC DELEGATES">
<Entry DisplayName="Public Delegates" Priority="100">
<Entry.Match>
<And>
<Access Is="Public" />
<Or>
<Kind Is="Delegate" />
<Kind Is="Event" />
</Or>
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="DELEGATES">
<Entry DisplayName="Delegates" Priority="100">
<Entry.Match>
<Or>
<Kind Is="Delegate" />
<Kind Is="Event" />
</Or>
</Entry.Match>
</Entry>
</Region>
<Region Name="PUBLIC PROPERTIES">
<Entry DisplayName="Public Properties">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Property" />
</And>
</Entry.Match>
<Entry.SortBy>
<Kind>
<Kind.Order>
<DeclarationKind>Autoproperty</DeclarationKind>
</Kind.Order>
</Kind>
</Entry.SortBy>
</Entry>
</Region>
<Region Name="PROPERTIES">
<Entry DisplayName="Properties">
<Entry.Match>
<Kind Is="Property" />
</Entry.Match>
<Entry.SortBy>
<Kind>
<Kind.Order>
<DeclarationKind>Autoproperty</DeclarationKind>
</Kind.Order>
</Kind>
</Entry.SortBy>
</Entry>
</Region>
<Region Name="INDEXERS">
<Entry DisplayName="Indexers">
<Entry.Match>
<Kind Is="Indexer" />
</Entry.Match>
</Entry>
</Region>
<Region Name="OPERATORS">
<Entry DisplayName="Operators">
<Entry.Match>
<Kind Is="Operator" />
</Entry.Match>
</Entry>
</Region>
<Region Name="CONSTRUCTORS">
<Entry DisplayName="Constructors">
<Entry.Match>
<Kind Is="Constructor" />
</Entry.Match>
<Entry.SortBy>
<Static/>
</Entry.SortBy>
</Entry>
</Region>
<Region Name="DESTRUCTORS">
<Entry DisplayName="Destructors">
<Entry.Match>
<Kind Is="Destructor" />
</Entry.Match>
<Entry.SortBy>
<Static/>
</Entry.SortBy>
</Entry>
</Region>
<Region Name="INTERFACE IMPLEMENTATIONS" Priority="100">
<Region Name="${0}" Priority="100">
<Region.GroupBy>
<ImplementsInterface Immediate="True" />
</Region.GroupBy>
<Entry DisplayName="Interface Members" Priority="100">
<Entry.Match>
<And>
<Kind Is="Member" />
<ImplementsInterface />
</And>
</Entry.Match>
<Entry.SortBy>
<ImplementsInterface Immediate="true" />
</Entry.SortBy>
</Entry>
</Region>
</Region>
<Region Name="PUBLIC METHODS">
<Entry DisplayName="Public Methods">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Method" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="METHODS">
<Entry DisplayName="Methods">
<Entry.Match>
<Kind Is="Method" />
</Entry.Match>
</Entry>
</Region>
<Region Name="OTHER MEMBERS">
<Entry DisplayName="All Other Members" />
</Region>
<Region Name="PUBLIC NESTED STRUCTS">
<Entry DisplayName="Public Nested Structs">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Struct" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="NESTED STRUCTS">
<Entry DisplayName="Nested STRUCTS">
<Entry.Match>
<Kind Is="Struct" />
</Entry.Match>
</Entry>
</Region>
<Region Name="PUBLIC NESTED CLASSES">
<Entry DisplayName="Public Nested Classes">
<Entry.Match>
<And>
<Access Is="Public" />
<Kind Is="Class" />
</And>
</Entry.Match>
</Entry>
</Region>
<Region Name="NESTED CLASSES">
<Entry DisplayName="Nested Classes">
<Entry.Match>
<Kind Is="Class" />
</Entry.Match>
</Entry>
</Region>
</TypePattern>
</Patterns>