web-dev-qa-db-ja.com

ReSharper-Microsoft.Contractsを使用するときに可能なヌル割り当て

契約による設計がチェックを必要とするためにnull参照が発生しないことをReSharperに示す方法はありますか?たとえば、次のコードは、7行目と8行目のReSharperで警告(_Possible 'null' assignment to entity marked with 'NotNull' attribute_)を発生させます。

_private Dictionary<string, string> _Lookup = new Dictionary<string, string>();

public void Foo(string s)
{
    Contract.Requires(!String.IsNullOrEmpty(s));

    if (_Lookup.ContainsKey(s))
        _Lookup.Remove(s);
}
_

本当に奇妙なのは、Contract.Requires(...)行を削除すると、ReSharperメッセージが消えることです。

更新

私はExternalAnnotationsを通じて解決策を見つけました。これは、以下のMikeによっても言及されています。 Microsoft.Contractsの関数に対してこれを行う方法の例を次に示します。

  • ExternalAnnotations ReSharperディレクトリの下に_Microsoft.Contracts_というディレクトリを作成します。
  • 次に、_Microsoft.Contracts.xml_というファイルを作成し、次のように入力します。
_<Assembly name="Microsoft.Contracts">
    <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>
</Assembly>
_
  • Visual Studioを再起動すると、メッセージが消えます。
53
HVS

:現在のR#8.0 EAPの時点で、この機能は含まれています。


コードコントラクトの現在の(つまり.NET 4.0)バージョンのソリューションは次のとおりです。

内部...\ExternalAnnotations\mscorlib\Contracts.xml、以下を追加します。

<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>
43
porges

独自のアサーションメソッドなどを作成する人のために、外部XMLファイルなしでこれらの属性を含めることができることを追加したいと思います。 Visual Studioで、_ReSharper > Options > Code Annotations_に移動し、_Copy default implementation to clipboard_ボタンをクリックします。次に、新しいファイル(ソリューション内の任意の場所)を作成し、クリップボードからコードを貼り付けます。これで、次のようなメソッドを作成できます。

_public class Require
{
    [AssertionMethod]
    public static void That(
        [AssertionCondition(AssertionConditionType.IS_TRUE)] 
        bool requiredCondition,
        string message = null)
    {
        ...
    }
...
}
_

これで、Require.That(a != null)を呼び出すと、aがnullの場合、この行を通過できないことがReSharperに示されます。 ExternalAnnotationsテクニックとは異なり、これはメソッドを使用するすべての人に機能し、追加の作業は必要ありません。

更新

Resharperは、バージョン7でコントラクトアノテーションモデルを変更しました。上記のメソッドは次のようになります。

_public class Require
{
    [ContractAnnotation("requiredCondition:false => halt")]
    public static void That(
        bool requiredCondition,
        string message = null)
    {
        ...
    }
...
}
_
18

できると思いますが、それは些細なことではありません。見てください コード注釈のためのResharperオンラインヘルプ

彼らは、Resharpersコード検査機能を強化するために、BCLクラスとNUnitフレームワーク(およびその他)に注釈を付けました。

たとえば、NUnitがアサートすると、AssertionMethodAttributeでアノテーションが付けられます。これは、Resharpersのコード検査に、Assert.IsNotNull(foo);を通過した場合に通知します。その場合、fooはnullであってはならず、「Possible'null '割り当て...」警告は生成されなくなります。

Contracts.Requiresメソッドに注釈を付けるxmlファイルを作成して、それがAssertのようなものであることを示すことができます。

5
Mike Two

アサーションを削除するとメッセージが消える理由は、R#がデフォルトで「楽観的」モードで動作するためです。実際にnullになる可能性があることを示す何かを行うまで、すべてがnullではないと想定します。これが、String.IsNullOrEmptyに呼び出しを追加したときに発生することです。あなたはsが実際にはnullである可能性があると述べています。その場合、Contract.Requiresメソッドが実行を停止することを認識していませんが、アノテーションを使用して解決しました。

R#5.0では、隅々で最悪の事態を想定する悲観的なモードに変更できます。

PorgesのXMLを使用して、AssertメソッドとAssumeメソッドのアノテーションを追加しました。他の人がメソッドを追加したい場合に備えて、この回答をウィキします。

<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>
3
Rory MacLeod

Resharperはバージョン7の時点でコントラクトアノテーションモデルを変更しました。

別のファイルが必要です。新しい場所(Metroアプリの場合のみ)は次のとおりです: "C:\ Program Files(x86)\ JetBrains\ReSharper\v7.1\Bin\ExternalAnnotations\.NETCore\System.Diagnostics.Contracts\Contracts.xml"

Visual Studio2012と.Net4.5およびResharper7.1を使用しています。

コンテンツ:

<Assembly name="System.Diagnostics.Contracts">
    <member name="M:System.Diagnostics.Contracts.Contract.Assert(System.Boolean)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Assert(System.Boolean, System.String)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Assume(System.Boolean)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Assume(System.Boolean, System.String)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Requires(System.Boolean)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Requires``1(System.Boolean)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Requires(System.Boolean,System.String)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Requires``1(System.Boolean,System.String)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Invariant(System.Boolean)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
    <member name="M:System.Diagnostics.Contracts.Contract.Invariant(System.Boolean,System.String)">
        <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
        <attribute ctor="M:JetBrains.Annotations.ContractAnnotationAttribute.#ctor(System.String)">
            <argument>condition:false=&gt;halt</argument>
        </attribute>
    </member>
</Assembly>
2
Flynn

TL; DR-条件付きコンパイルシンボル_CONTRACTS_FULL_をプロジェクトに追加します。

Contract.Requires(...)メソッドは、コード連絡先リライターを有効にして使用しない限り、空で無効になっています。リライタを手動で実行するか、(通常は)Visual Studioプロジェクトプロパティを介して有効にすることで、コンパイルおよびリライトされたバイナリにContract.Requires(...)コードを保持します。コードが機能することはわかっています。Resharperの警告を無視して、コードを実行してテストできます。

では、何が問題なのでしょうか。 Resharperは、コードコントラクトが実行されていることを認識していません。これは、実際には(ポスト)コンパイル時にのみ注入されるためです。 Resharperの目には、DEBUGプリプロセッサシンボルが機能するのと同じ方法で無効になり、VisualStudioがコンパイル済みバイナリの一部ではないコードの領域をグレー表示する方法が無効になります。

_#ifdef DEBUG
    Console.WriteLine("I'm in DEBUG mode, so this is probably a Debug build.");
#else
    Console.WriteLine("Let's assume this is a Release build.");
#endif
_

コード契約ユーザーマニュアル (第2章、最初の段落)および_ContractExtensions.cs_(コード契約イン​​ストールフォルダーに含まれる)のソースコードによると、_CONTRACTS_FULL_を設定する必要がありますそれをコンパイルする前に。 コントラクトメソッドは実際に実装されます with [ConditionalAttribute("CONTRACTS_FULL")] フラグが設定されていない限り、無視されます(コンパイル時には含まれません)。 Resharperはこのフラグを尊重し、設定されていない限り関数は実行されないと想定します。

_[ConditionalAttribute("CONTRACTS_FULL")]
public static void Requires(bool condition) { ... }
_

解決策:条件付きコンパイルシンボル_CONTRACTS_FULL_をプロジェクトに追加します。 コードコントラクトの使用Visual StudioおよびResharperを使用 HenningKrauseによるを参照してください。


(ソース: infinitec.de

Resharperチームに通知されました。 コード分析では、[コードコントラクト]プロジェクトのプロパティタブの設定は考慮されませんMicrosoftコードコントラクトのサポート

0
Joel Purra