毎週のプロジェクトの目標はこれでした。例外処理の典型的なエラーを表示する簡単なアナライザーを作成することです。 私の観点から最も痛いのは:
- throw exで例外を再スローします。
- 空のcatch {}またはcatch(Exception){}ブロックを使用して、すべての例外を「飲み込みます」。
- catchブロックの特定のブランチで例外を「飲み込む」。
- ログに ex.Messageメッセージのみを保存し、例外が発生した場所に関する潜在的に重要な情報を失います。
- catchブロックから新しい例外を誤ってスローします。
はじめに
アナライザーの開発を開始するには、 VS2015 CTPをインストールする必要があります(最も簡単な方法は既成の仮想ネットワークを使用することです)。その後、 VS 2015 SDK 、 .NET Compiler Platform SDK Templatesおよび.NET Compiler Platform Syntax Visualizerをインストールする必要があります 。 ビジュアライザーは、構文ツリーがどのように見えるか、それらを正しく分析する方法、および修正で新しいツリーを生成する方法を理解するために不可欠です。 最も重要なのは、ツールの正しいバージョンをインストールする必要があることです(CTP6の場合、すべてのVSIXパッケージはCTP6に対応している必要があります)。 Roslynプロジェクトのホームページには、常に最新のインストール手順があります。
開発チームは、アナライザーの作成が可能な限り単純で便利になるように素晴らしい仕事をしました。 新しいプロジェクトを作成し、テンプレートの[拡張性]-> [コード修正を使用した診断(Nuget + VSIX)]を選択し、アナライザー名を入力するだけで十分です。 その結果、アナライザー自体、単体テストを含むプロジェクト、インストーラーを含むプロジェクト(VSIX)の3つのプロジェクトが作成されます。 デフォルトでは、サンプルアナライザーがプロジェクトに追加され、小文字のタイプ名に関する警告が表示されます。
その後、テストを実行するか、VSIXプロジェクトを開始プロジェクトとして選択してF5を押します。 次に、アナライザーがインストールされたVisual Studioの別のインスタンスが起動され、小文字のすべてのタイプに対して警告が発行されます。
![](https://habrastorage.org/files/83c/176/ffc/83c176ffcfd74869a0619db38125856e.png)
分析装置の設置方法
アナライザーをインストールするには、次の3つの方法があります。
・VSIXパッケージを使用します。VSIXパッケージは、 Visual Studio Gallaryから直接、または「拡張機能と更新プログラム」からダウンロードできます。
・プロジェクトごとにアナライザーを手動でインストールします。
![](https://habrastorage.org/files/7cc/9b2/f6c/7cc9b2f6c6f749e1869bb3a3b313158f.png)
・また、アナライザーは、ライブラリと共にNuGetを介して配布することも、管理されたNuGetパッケージを介して単にインストールすることもできます。
![](https://habrastorage.org/files/ecc/86e/c53/ecc86ec537aa4474845a05243370b0e5.jpg)
同時に、パッケージへのリンクがソース管理にコミットされます。これにより、すべてのプロジェクト参加者が1セットのアナライザーを使用できるようになります。
テスタビリティ
ReSharper用のプラグインを開発するとき、ほとんどすべての単純な単体テストに欠けていました。 JetBrainsチームは深刻なテストインフラストラクチャを開発しましたが、すべてのテストは統合テストです。 R#には抽象テストはありません。それらはすべて、コンテキストアクションの可用性のテスト、「修正」の結果のテストなどのカテゴリのいずれかに分類されます。 このテストでは、結果を比較するためにアナライザーと別のファイルを実行するコードでcsファイルをスリップする必要があります。 ビジネスロジックを単独でテストすることはできません。
ロズリンでは、彼らはより単純な道を進んだ。 アナライザーは、ファイルまたは文字列からのテストで簡単に作成できる構文およびセマンティックツリー(構文ツリーおよびセマンティックツリー)で動作します。 そのため、テストではアナライザー自体を確認するか、構文ツリーのフラグメントを渡すことでビジネスモデルを確認できます。
[TestMethod] public void SimpleTestWarningOnEmptyBlockThatCatchesException() { var test = @" using System; namespace ConsoleApplication1 { class TypeName { public static void Foo() { try { Console.WriteLine(); } {on}catch(System.Exception) {} } } }"; var warningPosition = test.IndexOf("{on}"); var diagnostic = GetSortedDiagnostics(test.Replace("{on}", "")).Single(); Assert.AreEqual(EmptyCatchBlockAnalyzer.DiagnosticId, diagnostic.Id); Assert.AreEqual("'catch(System.Exception)' block is empty. Do you really know what the app state is?", diagnostic.GetMessage()); Assert.AreEqual(warningPosition, diagnostic.Location.SourceSpan.Start); }
Roslynプロジェクトには数百万行のコードがありますが、十分に構造化されており、多数の追加のアセンブリをロードする必要がないため、テストが迅速に実行されることも非常に喜ばしいことです。
受け取った機会
それで、結果のアナライザーは何ができますか? 現在、6つの基本ルールをサポートしています。
![](https://habrastorage.org/files/929/0db/ee5/9290dbee5c6a47d5afdea43d72fefa9e.png)
それらのそれぞれは、例で説明するのが最も簡単です。 いくつかの例は、理想からかけ離れたアニメーションを使用して示されています。 VS2015は仮想マシンにインストールされており、画像キャプチャは同時にわずかに歪んでいます。 しかし、本質は明らかです。
1.有害と考えられる空のcatchブロック !
例外を処理する際の最も深刻なコード臭いは、空のcatchまたはcatch(Exception)ブロックですべての例外を完全に抑制することです:
![画像](https://habrastorage.org/getpro/habr/post_images/7f5/60b/11f/7f560b11fb2b470418b09a83f605fd53.gif)
2.有害と見なされる例外を飲み込む
catch {}ブロックを使用してすべての例外をキャッチする人のために、ボイラー上の特別な場所を準備する必要があります。 この場合の修正は非常に簡単です。
![画像](https://habrastorage.org/getpro/habr/post_images/bf7/fbc/7f3/bf7fbc7f3ec1d3551784ef568f0348e9.png)
3.キャッチブロックが例外を飲み込む
例外の抑制について警告する別のパーサー。 catchブロックは空ではないかもしれませんが、例外を「飲み込む」可能性があります。 この場合、特にcatchブロックのブランチの1つだけで例外が抑制されている場合、正しい修正を見つけるのは非常に困難です。
![画像](https://habrastorage.org/getpro/habr/post_images/546/40c/7e4/54640c7e4cf30163912c987cdcc6e99a.jpg)
はい、Roslinを使用せずにこのようなアナライザーを作成しようとすると、数か月の作業が必要になります。 Roslinには制御フロー分析のサポートが組み込まれているため、このアナライザーを作成するのは難しくありませんでした。
4.例外を適切に再スローする
これは、例外のスローがthrow exを使用して行われる場合の最も一般的なエラーの1つです。 、 throwを使用しません。 念のため、最初のケースでは、元の例外のスタックトレースが失われ、catchブロックがソースであるように見えることを思い出します。
![画像](https://habrastorage.org/getpro/habr/post_images/fe6/7f0/ca6/fe67f0ca67f400c307ce4122bc3b9b9b.gif)
5.有害と考えられるex.Messageのトレース
もう1つの一般的な例外処理エラーは、 ex.Messageとex.StackTraceのみがコンソールまたはログに保存される場合です。 例外は非常に頻繁に例外ツリーを形成するため、最上位のメッセージには有用なものがまったく含まれていない可能性があります。
この分析は、catchブロックがMessageプロパティを使用(「監視」)するが、例外内部の詳細に関心がない場合に警告を生成します。
![画像](https://habrastorage.org/getpro/habr/post_images/313/026/2b1/3130262b113f94f4335660dcd0096002.gif)
例外をトレースするための非常に美しいモデルのため、1月1日に作業を開始し、製品にホットフィックスをアップロードする必要がありました。これにより、システムで何が起こっているかが明確になります。 ex.Messageのみを記録しないでください ! 絶対に!
6.キャッチされた例外を内部例外として追加します
catchブロックは例外をスローする場合がありますが、それでも元の例外に関する情報は失われる可能性があります。 これを回避するには、新しい例外に元の例外をネストされた例外として含める必要があります。
このアナライザーは、新しい例外を生成するためのコードをチェックし、元の例外が使用されていない場合、ネストされた例外として追加することを提案します(当然、このため、生成された例外には、 ストリングとExceptionのパラメーターを受け入れるコンストラクターが必要です):
![画像](https://habrastorage.org/getpro/habr/post_images/8d1/ff2/844/8d1ff2844b8b19fcac2d90a2c8f64401.gif)
結論の代わりに
少なくともこの投稿では、アナライザー自体の開発に専念したくありません。 ネットには非常に良い例があります(記事の最後にリンクがあります)。さらに、私はこの問題の専門家とは考えていません。 この投稿のポイントは、Roslynがあなたのためにすべての汚い仕事をするので、あなた自身の手でアナライザーを作成することの容易さを示すことです。 そのため、チーム内のコードに突然典型的な問題が発生し、特定のコーディング標準を形式化する場合は、独自のアナライザーを作成することをお勧めします。
サイトリンク
- GitHubの例外アナライザー
- Nuget.orgの例外アナライザー (Add NuGetパッケージから利用可能、api.nuget.orgではなく、nuget.orgのみをフィードとして使用する必要があります)
- Visual Studio Galleryの例外アナライザー
パーサーの作成に関するMSDNマガジンの紹介記事:
Z.Y. 例外アナライザーに希望があり、口whiを吹くなら、喜んで追加します。