使用 dotnet format 格式化代碼
使用 dotnet format 格式化代碼
Intro
dotnet-format 在之前的版本是一個(gè)獨(dú)立的命令行工具,在 .NET 6 里已經(jīng)成為了 SDK 的一部分,我們可以使用,使用 dotnet format 我們可以結(jié)合 editorconfig 保持代碼風(fēng)格的一致,我們也可以將 dotnet format 作為一個(gè) CI 服務(wù)來運(yùn)行,自動(dòng) format 我們的代碼或驗(yàn)證代碼是否符合我們的代碼風(fēng)格
Editorconfig
EditorConfig 有助于為跨各種編輯器和 IDE 處理同一項(xiàng)目的多個(gè)開發(fā)人員維護(hù)一致的編碼風(fēng)格
Editorconfig 是用來指定文件的格式的,在 .NET 里,微軟擴(kuò)充了 editorconfig 的用法,我們可以把 C# 的一些編碼風(fēng)格甚至一些錯(cuò)誤的級(jí)別也加入其中,從而可以通過 editorconfig 來統(tǒng)一代碼的風(fēng)格。
很多編輯器和 IDE 都支持 Editorconfig,包括我們常用 VS,Rider、VS Code/Sublime 等
Sample
C# 10 開始支持了 file-scoped namespace,我們可以使用 editorconfig 來配置使用 file-scoped 風(fēng)格的命名空間聲明方式,在之前的文章中,我們?cè)?jīng)介紹過,可以在 editorconfig 中配置 csharp_style_namespace_declarations=file_scoped:suggestion 來使得 VS 創(chuàng)建項(xiàng)目的時(shí)候默認(rèn)使用 file-scoped 風(fēng)格,這里的 suggestion 是一個(gè)提示級(jí)別,我們也可以將此級(jí)別提高成 info/warning 甚至 error,dotnet format 默認(rèn)自動(dòng) format 級(jí)別為 warning 及以上級(jí)別的規(guī)則
所以我們可以將上面的級(jí)別改成 warning,然后在項(xiàng)目目錄下運(yùn)行 dotnet format,然后我們項(xiàng)目中所有類型的命名空間風(fēng)格就會(huì)從傳統(tǒng)的風(fēng)格變成新的 file-scoped 風(fēng)格,可以參考這個(gè) commit https://github.com/WeihanLi/WeihanLi.Npoi/commit/201427b95f2bc23e97e2be595bc103301b7898e3
下面這個(gè)變更就是由 dotnet format 更改的

一個(gè)命令遷移項(xiàng)目中所有文件的命名空間風(fēng)格為新的 file-scoped 風(fēng)格,是不是很方便呢~~
當(dāng)然不僅僅是命名空間風(fēng)格,我們還可以在 editorconfig 中定義其他很多的代碼風(fēng)格,甚至我們也可以定義一些第三方分析器的診斷級(jí)別,具體規(guī)則可以參考微軟的這個(gè)文檔:https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options?view=vs-2019
有一些代碼格式在 VS 中也是可以配置的,但是個(gè)人更加推薦使用 editorconfig 的方式,這樣別人要修改某個(gè)項(xiàng)目的時(shí)候,也不需要修改 VS 的配置,只需要遵循 editorconfig 的風(fēng)格就可以了,配置即代碼,在任何地方都是一樣的,也不需要關(guān)注 IDE。
CI Service
我們可以把 dotnet format 做成一個(gè) CI 服務(wù)來保證自己的代碼風(fēng)格始終是一致的,我們可以有多個(gè)選擇
第一種方式,我們只做代碼格式的驗(yàn)證,我們可以使用 dotnet format --verify-no-changes 來驗(yàn)證格式是否有問題,如果格式有問題,exitcode 將不會(huì)是 0,而是 2,也就意味著會(huì) CI 失敗
Github Actions CI 配置示例如下:
name:?dotnet-format
on:?[pull_request]
jobs:
??build:
????runs-on:?ubuntu-latest
????steps:
????-?uses:?actions/checkout@v1
????-?name:?Setup?.NET?6
??????uses:?actions/setup-dotnet@v1
??????with:
????????dotnet-version:?'6.0.x'
????-?name:?build
??????run:?dotnet?build
????-?name:?check?format
??????run:?dotnet?format?--verify-no-changes
第二種,我們可以直接提交一個(gè) commit 來修復(fù)不正確的格式,運(yùn)行 dotnet format 的時(shí)候會(huì)嘗試修復(fù)項(xiàng)目的代碼格式,修復(fù)之后我們把這些修復(fù)后的文件變成提交成一個(gè) commit 然后推送到我們的代碼庫就可以了,Github Actions CI 示例如下:
name:?dotnet-format
on:
??push:
????branches:?[?dev?]
jobs:
??build:
????runs-on:?ubuntu-latest
????steps:
????-?uses:?actions/checkout@v1
????-?name:?Setup?.NET?6
??????uses:?actions/setup-dotnet@v1
??????with:
????????dotnet-version:?'6.0.x'
????????include-prerelease:?true
????-?name:?build
??????run:?dotnet?build
????-?name:?format
??????run:?dotnet?format
????-?name:?check?for?changes
??????run:?|
????????if?git?diff?--exit-code;?then
??????????echo?"has_changes=false"?>>?$GITHUB_ENV
????????else
??????????echo?"has_changes=true"?>>?$GITHUB_ENV
????????fi
????-?name:?Commit?and?Push
??????if:?${{?env.has_changes?==?'true'?}}
??????shell:?bash
??????run:?|
????????git?config?--local?user.name?"github-actions[bot]"
????????git?config?--local?user.email?"[email protected]"
????????git?add?-u
????????git?commit?-m?"Automated?dotnet-format?update?from?commit?${GITHUB_SHA}?on?${GITHUB_REF}"
????????git?log?-1
????????remote_repo="https://${GITHUB_ACTOR}:${{secrets.GITHUB_TOKEN}}@github.com/${GITHUB_REPOSITORY}.git"
????????git?push?"${remote_repo}"?HEAD:${GITHUB_REF}
這里的 CI 直接運(yùn)行了 dotnet format 命令,然后會(huì)通過 git 命令來檢查是否有文件變更,如果有文件變更就會(huì)生成一個(gè) commit 并推送到代碼庫
前面的變更就是 CI 自動(dòng)提交的 commit? 的一部分,當(dāng)我提交代碼時(shí)就會(huì)自動(dòng)跑?dotnet format 如果有變更就會(huì)提交到倉庫一個(gè)新的格式化的提交,下面兩個(gè)commit 就是?CI 自動(dòng)提交的一個(gè)示例

Github actions 可以參考
https://github.com/WeihanLi/WeihanLi.Npoi/blob/dev/.github/workflows/dotnet-format.yml https://github.com/WeihanLi/WeihanLi.Npoi/blob/dev/.github/workflows/dotnet-format-pr-validation.yml
More
除了上面的這些基本用法,dotnet format 還有更多的選項(xiàng),可以通過 --severity 指定嚴(yán)重等級(jí),默認(rèn)是 warning,也可以手動(dòng)指定為 info 或者 error,另外可以只 format 空格 dotnet format whitespace、代碼風(fēng)格 dotnet format style 或者第三方的分析器 dotnet format analyzers
更多可以參考 dotnet format 的介紹:https://github.com/dotnet/format/blob/main/README.md
總體上使用下來,感覺還是挺不錯(cuò)的,但是目前有遇到兩個(gè)問題,一個(gè)是在使用框架條件編譯的時(shí)候
也就是代碼里有 #if NET6_0 類似代碼時(shí)格式可能會(huì)有問題,出現(xiàn)一段被注釋的代碼,這里有一個(gè)示例,但是手動(dòng)改了以后似乎沒有這個(gè)問題了,只遇到過一次,而且 review 了更改的代碼也沒什么問題

代碼太多了截圖了一部分,感興趣的可以直接看對(duì)應(yīng) commit 的文件:https://github.com/WeihanLi/WeihanLi.Common/blob/3b080c08c87fa24d99a938a8b3173fb7ec3e92de/src/WeihanLi.Common/Helpers/SecurityHelper.cs
另外一個(gè)問題是項(xiàng)目中有 source generator 的時(shí)候會(huì) format 失敗,提了一個(gè) issue,暫時(shí)還沒有解決方案,感興趣的可以參考:https://github.com/dotnet/format/issues/1461
References
https://github.com/dotnet/format https://github.com/dotnet/format/issues/1268 https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options?view=vs-2019 https://github.com/dotnet/format/blob/main/docs/Supported-.editorconfig-options.md https://github.com/WeihanLi/WeihanLi.Npoi/commit/201427b95f2bc23e97e2be595bc103301b7898e3 https://github.com/WeihanLi/WeihanLi.Npoi/blob/dev/.github/workflows/dotnet-format.yml https://github.com/WeihanLi/WeihanLi.Npoi/blob/dev/.github/workflows/dotnet-format-pr-validation.yml https://github.com/dotnet/format/issues/1461
