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

有什么方法可以向ReSharper表明由于devise合同需要检查而不会出现空引用? 例如,下面的代码将在第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消息就会消失。

更新

我通过ExternalAnnotationsfind了解决scheme,Mike在下面也提到了这个解决scheme。 下面是一个如何为Microsoft.Contracts中的函数实现的示例:

  • ExternalAnnotations ReSharper目录下创build一个名为Microsoft.Contracts的目录。
  • 接下来,创build一个名为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,消息消失!

注意 :从目前的R#8.0 EAP开始,包含了这个function。


这里是代码合同的当前(即.NET 4.0)版本的解决scheme:

...\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> 

我想补充一点,对于编写自己的断言方法的人来说,你可以包含这些属性而不需要外部的XML文件。 在Visual Studio中,转到“ ReSharper > Options > Code Annotations ,然后单击“ Copy default implementation to clipboardbutton。 然后创build一个新的文件(在你的解决scheme中你想要的任何地方)并粘贴到剪贴板的代码中。 现在,你可以创build像这样的方法:

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

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

更新

Resharper从版本7开始已经改变了他们的契约注解模型。现在看看上面的方法是什么样的:

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

我认为你可以,但这不是微不足道的。 看看Resharper在线帮助代码注释

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

例如,NUnit断言它们用AssertionMethodAttribute进行注释。 这告诉Resharpers代码检查,如果你通过了一个Assert.IsNotNull(foo); 那么foo一定不能为null,也不会产生“Possible”null“赋值…”警告。

您可以生成一个注释Contracts.Requires方法来指示它就像一个Assert的XML文件。

消除断言时消息的原因是默认情况下R#工作在“乐观”模式。 它假定一切都是非空的,直到你做了一些表明它实际上可以为空的东西。 当您将调用添加到String.IsNullOrEmpty时会发生这种情况。 你说的s可能实际上是空的。 它只是不知道, Contract.Requires方法将停止执行,如果是这样的话,但你解决与注释。

在R#5.0中,您可以更改为悲观模式,假设每个angular落都是最糟糕的。

我采取了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> 

从第7版开始,Resharper已经改变了他们的合约注解模型。

你需要一个不同的文件。 新位置(我猜测只适用于Metro应用程序)是:“C:\ Program Files(x86)\ JetBrains \ ReSharper \ v7.1 \ Bin \ ExternalAnnotations \ .NETCore \ System.Diagnostics.Contracts \ Contracts.xml”

我正在使用Visual Studio 2012和.Net 4.5和Resharper 7.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> 

TL; DR – 将条件编译符号CONTRACTS_FULL添加到您的项目中。

除非您启用并使用“代码联系人”重写器,否则Contract.Requires(...)方法将为空并禁用。 通过手动运行重写器,或(通常)通过Visual Studio项目属性启用它,您将保留Contract.Requires(...)代码在编译和重写的二进制文件中。 你知道代码会工作,而忽略了Resharper警告,你可以运行它并testing。

那么问题是什么? Resharper不知道代码合约正在运行,因为它们实际上只是在(后)编译时注入的。 在Resharper的眼中,它和DEBUG预处理器符号一样是被禁用的,Visual Studio如何将代码中不会被编译的二进制文件的一部分变成灰色的区域。

 #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 

根据Code Contracts用户手册 (第2章,第1段)和ContractExtensions.cs (包含在Code Contracts安装文件夹中)中的源代码,需要在编译CONTRACTS_FULL之前设置CONTRACTS_FULL 。 契约方法实际上是通过[ConditionalAttribute("CONTRACTS_FULL")] ,忽略(不包括在编译时),除非标志被设置。 Resharper尊重这个标志,并且假定这个函数在设置之前不会运行。

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

解决scheme:将条件编译符号CONTRACTS_FULL添加到您的项目中。 请参阅使用代码合同Visual Studio和 Henning Krause的Resharper 。

http://www.infinitec.de/image.axd?picture=Windows-Live-Writer/Using-CodeContracts-with-Resharper/05970F39/ConditionalSymbol.png

Resharper团队已经通知了; 代码分析不考虑“代码合同”项目属性选项卡上的设置 , 支持Microsoft代码合同 。