ヒント:Microsoft CodeContractsでReSharperを使用する

数時間の手続きの後、短いメモを書くことにしました。答えはすぐにオンラインではなく、断片的で英語ではありません。

HabréのMicrosoft CodeContractsについてすでに書いていますが 、Visual Studio用のライブラリおよびツールキットであり、C#で「契約プログラミング」の要素を使用できます。

私たちは比較的最近プロジェクトでCodeContracts(以降、単に「契約」と呼びます)を使い始め、一般的には満足していますが、コンパイル時間をさらに数秒待っています。

もちろん、ReSharperを使用しますが、追加の紹介は不要です。

しかし、効果的に機能するためには、これらの2つのツールを少し友達にする必要があるという事実には、いくつかのニュアンスがあります。

Nuance 1.メソッドの呼び出しはスキップされます

まず、ReSharperはデフォルトで、次のような契約への呼び出しの一部がアセンブリから除外され、容赦なく「ゴミ」になると考えていることに気付くでしょう。

ReSharperはコンパイラが契約の検証を除外すると考えています

実際、これらの呼び出しはアセンブリから除外さませんContract.RequiresContract.Ensuresなどの契約の一部のメソッドは[Conditional("CONTRACTS_FULL")]属性でマークされますが、 CONTRACTS_FULLフラグは、コンパイルの前に、プロジェクトのビルド段階で既に契約メカニズムによって設定されているため、ReSharper '設定で事前に定義されたコンパイル文字のリストを確認します。

通常のコンパイル後、コントラクトメカニズムは結果のILコードをインスツルメントし、これらの呼び出しを__ConstractRuntimeクラスの他の呼び出しに置き換えます。 Reflectorを使用すると、これを簡単に詳細に確認できます(まだ無料ですが、急いでください)。

ただし、 Contract.Assertの呼び出しは最初からコードに存在し、実行時に書き換えなく動作します。 それらは[Conditional("CONTRACTS_FULL")]としてマークされるだけでなく、 Conditional("DEBUG")としてもマークされます。 その結果、デバッグ構成( DEBUGシンボルが定義されている場合)では、ReSharper自身がこの呼び出しが本物であることを理解しています。

それでは、ReSharperにContract.Requiresも「正直な」呼び出しであり、エディターで「台無しにすべきではない」ことをどのように説明しますか? ランタイムコントラクトチェックをオンにしているプロジェクト構成のプロジェクトビルドの[ビルド]タブで、条件付きコンパイルシンボルCONSTRACTS_FULLを設定するだけです(プロジェクトオプション[コードコード]> [ランタイムチェック])。

ReSharperは、欠落しているメソッドをすぐに「見る」でしょう! もちろん、1つのタブと別のタブで既に設定されているフラグの意味を繰り返すことはあまり便利ではありませんが、少なくともプロジェクトの構成ごとに1回は実行できます。

JetBrainsはすでにこの問題について知っています。そして、将来のバージョンでは、ReSharperがすぐに契約をサポートすることを願っています。

Nuance 2.考えられるNullReferenceException

契約でReSharperの機能を最大化するために行う必要がある別の設定は、価値分析設定です。 特に、ReSharperは、 nullメソッドパラメーターのチェックの有無を検出できるため、そのようなチェックがない場合に引数オブジェクトのメソッドにアクセスすると、 NullReferenceException例外がスローされる可能性があることを警告します。

ReSharperは、契約がnullの引数をチェックすることを理解していません

ただし、デフォルトでは、ReSharperは契約の前提条件Contract.Requires(visitor != null)を追加すると、 null必要なチェックが提供されると推測できません。

幸いなことに、ReSharperにはいわゆるメカニズムがあります。 外部アノテーション。これにより、ReSharperの追加のメタ情報を使用して、サードパーティライブラリのクラスとメソッドをマークアップできます。 具体的には、ReSharperが契約チェックを「認識」し始めるために、 Contractクラスのメソッドのメタ記述を含む特別なxmlファイルを\ Bin \ ExternalAnnotations \ mscorlib \フォルダに追加する必要があります。

 <assembly name="mscorlib"> <member name="M:System.Diagnostics.Contracts.Contract.Assert(System.Boolean)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Assert(System.Boolean, System.String)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Assume(System.Boolean)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Assume(System.Boolean, System.String)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Requires(System.Boolean)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Requires``1(System.Boolean)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Requires(System.Boolean,System.String)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Requires``1(System.Boolean,System.String)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Invariant(System.Boolean)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> <member name="M:System.Diagnostics.Contracts.Contract.Invariant(System.Boolean,System.String)"> <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/> <parameter name="condition"> <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)"> <argument>0</argument> </attribute> </parameter> </member> </assembly> 

その後、すべてが適切に配置され、CodeContractsの使用が原因で誤っている場合を気にせずに、お気に入りのツールのヒントに頼ることができます!

Source: https://habr.com/ru/post/J114067/


All Articles