ReSharper - 使用Microsoft.Contracts时可能的空值分配

HVS*_*HVS 52 c# resharper design-by-contract code-contracts microsoft-contracts

有没有办法向ReSharper表明由于按合同设计需要检查,不会出现空引用?例如,以下代码将Possible 'null' assignment to entity marked with 'NotNull' attribute在第7行和第8行的ReSharper中引发warning():

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);
}
Run Code Online (Sandbox Code Playgroud)

真正奇怪的是,如果删除该Contract.Requires(...)行,ReSharper消息就会消失.

更新

我通过ExternalAnnotations找到了解决方案,Mike也在下面提到过.以下是如何在Microsoft.Contracts中为函数执行此操作的示例:

  • 创建一个Microsoft.ContractsExternalAnnotationsReSharper目录下调用的目录.
  • 接下来,创建一个名为的文件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>
Run Code Online (Sandbox Code Playgroud)

  • 重新启动Visual Studio,消息就消失了!

por*_*ges 43

注意:从当前的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>
Run Code Online (Sandbox Code Playgroud)


Str*_*ior 18

我想补充一点,对于编写自己的断言方法等的人来说,可以在没有外部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)
    {
        ...
    }
...
}
Run Code Online (Sandbox Code Playgroud)

现在任何调用Require.That(a != null)都会向ReSharper表明,如果a为null ,则无法通过此行.与ExternalAnnotations技术不同,这适用于使用您的方法的任何人,而无需任何额外的工作.

更新

从版本7开始,Resharper已经更改了合同注释模型.以下是上述方法现在的样子:

public class Require
{
    [ContractAnnotation("requiredCondition:false => halt")]
    public static void That(
        bool requiredCondition,
        string message = null)
    {
        ...
    }
...
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*Two 5

我想你可以,但这不是微不足道的.查看Resharper在线帮助以获取代码注释

他们注释了BCL类和NUnit框架(以及更多)以增强Resharpers代码检查功能.

例如,使用NUnit断言,它们使用AssertionMethodAttribute进行注释.这告诉Resharpers代码检查,如果你通过Assert.IsNotNull(foo); 然后foo不能为null,它不会产生"可能'null'赋值..."警告.

您可以生成一个注释Contracts.Requires方法的xml文件,以指示它就像Assert一样.