tmori3y2のブログ

主にWindowsのプログラムなど

thisの使い方 - StyleCop vs FxCop

tmori3y2.hatenablog.com

LinqPadの記事から、こっそりStyleCop.Analyzersを使っていた。

FxCop相当のCode Analysisとは違い、標準で入っていないので敬遠していたが、

opcdiary.net

こちらの記事で気軽に試せると知って試しに入れてみた。

今、読み返してみたけど、ちょっと恥ずかしいのを見つけてしまった。

の部分の警告がstylecop.jsonを追加しても消えないので、以下のように抑制していた。

ブログの記事を、下までよ~く読むとちゃんと、

「プロジェクトファイルを編集してね」

と書いてある。

「ちゃんと読めよ・・・」

と自分でツッコミ入れておく。

「まあ、プロジェクトファイル編集しなくても、BuildActionをAdditionalFilesに変更すれば良いみたいだけど・・・」

さて、GlobalSuppressions.csで設定している別の抑制が今回のネタ。実は、GlobalSuppressions.csに入れたことを後悔している。

thisを付けないとSA1101の指摘を受けて、thisを付けるとIDE0003の指摘を受ける。

StyleCopのIssueでもちょっと議論になったことがある。

github.com

要は、クラスメンバーに、ちゃんとthisを付ける(SA1101)か?省略できる部分は省く(IDE0003)か?という話。

StyleCopAnalyzers/SA1101.md at master · DotNetAnalyzers/StyleCopAnalyzers · GitHub

では、以下のように述べられている。

1) base/thisを明示せずに、メンバーにアクセスした場合に指摘される

2) StyleCopのデフォルトでは、"_"やハンガリアン記法の"m_"を名前に含める方法でのフィールドの宣言を認めていない

3) thisを付けることにより、インスタンスメンバーと即座に認識可能であるという利点がある

4) thisを付けることにより、静的メンバーと即座に分離可能であるという利点がある

5) インテリセンスにより、すぐに入力補間できるという利点がある

StyleCopAnalyzers/SA1100.md at master · DotNetAnalyzers/StyleCopAnalyzers · GitHub

も併せてチェックしておきたい。

IDE0003は.NET coreのC# Coding Styleから来ていると思う。

3) internal/privateフィールドについては"_"を付けること。staticなinternal/privateフィールドについては"s_"を、thread staticなinternal/privateフィールドについては"t_"を付けること

4) thisは絶対に必要な場合以外は避けること

StyleCop 1)は、設計で逃げられる部分もあるが、後から挙動を変えてしまうこともあるので、常に指摘されることで、意識を途切れさせない意味は大きい。

デフォルトではOnでIDE0003をOffにして、必要に応じてIDE0003をOnでSA1101をOffにするスタイルが無難であると思う。

今回の指摘部分は、CultureInfoのインスタンスからプロパティを初期化している部分なので、thisを必ず使用しなければならないケースには当たらない。

一点、まずい部分は、GlobalSuppressions.csに書いている部分で、意図的にthisを抑制しているという意識が低くなるので、対象部分のみ抑制して、理由のコメントを付けた方がメンテナンス性が向上すると思う。

「一方で、コードジェネレータが生成するコードは、手動修正は望ましくないので、原則としてSA1100/SA1101はOnにしてチェックしておく配慮がジェネレータの作者には必要ではないかと思う。」

以下、thisから逸れて、半分宗教論争になってしまうが、StyleCop 2)には、激しく同意します。

Javaから輸入されてきたからか、自動プロパティで内部的に"_"が付けられてるからか、MVVMを初め、結構使用されるようになってしまった。

しかし、自動プロパティのそれは、C/C++がそうであったように、或いはCOM相互運用のデフォルトのクラスインターフェースが、クラス名に"_"を付けて自動で生成されるように、コンパイラ生成シンボルで使用される予約されたアンダースコアであって、ユーザ定義フィールドとの衝突を避けるためのものだと思う。

それをユーザ定義フィールドで使用するのは、はっきり言って誤用と思う。

「大体、"m_"はアウトと言っておきながら、mを外した"_"はOKって、矛盾してるだろう・・・」

と思うのだが。

Framework Design GuidelinesNames of Type Members

では、public/protectedフィールドに限定してハンガリアン記法やアンダースコアを禁止しているだけなので、

「 internal/privateフィールドはどうぞ」

なのかも知れないが、そもそもハンガリアン記法や"m_"、"s_"などのスコープ限定プレフィックス使用の弊害に対するアンチテーゼだった筈。

この点に関するCoding Guidelines | Monoが面白い。

「The use of “m_” and “_” as prefixes for instance members is highly discouraged.」

と、ボロクソである。

まあ、Monoも小文字の単語の区切りの"_"はOKとか、“my_"はOKとか微妙なところはある。

もっとも、"my_"に関しては、単語の区切りの"_"を認めてしまっているので、唯の単語扱いなんだろう。

Xamarinも合流したことだし、この辺は.netコミュニティでも何らかの結論を出すかもしれない。

また、規約が作られたのも、intellisenseの技術が発達していなかった時代のもので、スコープ認知性に関する下りは、エディタやコード解析技術の進歩とともに、解消されて来るので、そこに"_"を使用する必然性は廃れてくるのではないかと個人的には思っている。