ReSharper - 使用 Microsoft.Contracts 时可能出现空分配
有没有什么方法可以向 ReSharper 表明由于 Design-by-Contract 需要检查而不会发生空引用? 例如,以下代码将在 ReSharper 的第 7 行和第 8 行中引发警告(Possible 'null' assignment to token 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,该消息就会消失!
Is there any way to indicate to ReSharper that a null reference won't occur because of Design-by-Contract Requires checking? For example, the following code will raise the warning (Possible 'null' assignment to entity marked with 'NotNull' attribute
) in ReSharper on lines 7 and 8:
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);
}
What is really odd is that if you remove the Contract.Requires(...)
line, the ReSharper message goes away.
Update
I found the solution through ExternalAnnotations which was also mentioned by Mike below. Here's an example of how to do it for a function in Microsoft.Contracts:
- Create a directory called
Microsoft.Contracts
under theExternalAnnotations
ReSharper directory. - Next, Create a file called
Microsoft.Contracts.xml
and populate like so:
<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>
- Restart Visual Studio, and the message goes away!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我想补充一点,对于编写自己的断言方法等的人来说,您可以在没有外部 XML 文件的情况下包含这些属性。 在 Visual Studio 中,转到
ReSharper > 选项> 代码注释
并单击将默认实现复制到剪贴板
按钮。 然后创建一个新文件(解决方案中您想要的任何位置)并粘贴剪贴板中的代码。 现在,您可以创建如下方法:现在,任何对
Require.That(a != null)
的调用都会向 ReSharper 表明,如果a
则您无法越过这一行> 为空。 与外部注释技术不同,这适用于任何使用您的方法的人,而无需他们进行任何额外的工作。更新
Resharper 从版本 7 开始更改了其合约注释模型。以上方法现在如下所示:
I'd like to add that for people writing their own assertion methods and such, you can include these attributes without an external XML file. In Visual Studio, go to
ReSharper > Options > Code Annotations
and click theCopy default implementation to clipboard
button. Then create a new file (anywhere you want in your solution) and paste in the code from the clipboard. Now, you can create methods like this:Now any call to
Require.That(a != null)
will indicate to ReSharper that you can't get past this line ifa
is null. Unlike the ExternalAnnotations technique, this will work for anyone using your methods, without any additional work on their part.Update
Resharper has changed their contract annotation model as of version 7. Here's what the above method would look like now:
我认为你可以,但这并不是微不足道的。 看看Resharper代码注释在线帮助
他们注释了BCL 类和 NUnit 框架(以及更多)来增强 Resharpers 代码检查功能。
例如,对于 NUnit 断言,它们使用 AssertionMethodAttribute 进行注释。 这告诉 Resharpers 代码检查,如果您通过了 Assert.IsNotNull(foo); 那么 foo 一定不能为 null,并且它不会再产生“可能的 'null' 赋值...”警告。
您可以生成一个 xml 文件来注释 Contracts.Requires 方法,以表明它就像一个 Assert。
I think you can but it isn't trivial. Take a look at Resharper online help for code annotation
They annotated the BCL classes and the NUnit framework (and more) to enhance Resharpers code inspection capabilities.
For example with the NUnit asserts they annotated with an AssertionMethodAttribute. This tells Resharpers code inspection that if you got past an Assert.IsNotNull(foo); then foo must not be null and it won't produce the "Possible 'null' assignment..." warning anymore.
You could produce an xml file annotating the Contracts.Requires method to indicate that it is just like an Assert.
当您删除断言时,该消息消失的原因是 R# 默认情况下以“乐观”模式工作。 它假设所有内容都是非空的,直到您执行某些操作表明它实际上可以为空。 这就是当您添加对
String.IsNullOrEmpty
的调用时会发生的情况。 您声明s
实际上可能为 null。 它只是不知道在这种情况下Contract.Requires
方法将停止执行,但您通过注释解决了这个问题。在 R# 5.0 中,您可以更改为悲观模式,在每个角落都假设最坏的情况。
The reason the message goes away when you remove the assertion is that R# works in an "optimistic" mode by default. It assumes everything is non-null until you do something that indicates it can actually be null. That's what happens when you add the call to
String.IsNullOrEmpty
. You're stating thats
could actually be null. It just isn't aware that theContract.Requires
method will stop execution if that's the case, but that you solved with the annotation.In R# 5.0 you can change to a pessimistic mode that assumes the worst at every corner.
我采用了 Porges 的 XML 并为 Assert 和 Assume 方法添加了注释。 如果其他人想要添加更多方法,我将维基这个答案。
I took Porges' XML and added annotations for the Assert and Assume methods. I'll wiki this answer in case other people want to add more methods.
Resharper 从版本 7 开始更改了其合约注释模型。
您需要不同的文件。 新位置(我想仅适用于 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。
内容:
Resharper has changed their contract annotation model as of version 7.
You need a different file. The new location (I guess only for Metro apps) is:
"C:\Program Files (x86)\JetBrains\ReSharper\v7.1\Bin\ExternalAnnotations\.NETCore\System.Diagnostics.Contracts\Contracts.xml"
I am using Visual Studio 2012 and .Net 4.5 and Resharper 7.1.
Content:
TL;DR - 将条件编译符号
CONTRACTS_FULL
添加到您的项目中。Contract.Requires(...)
方法为空且已禁用,除非您启用并使用代码联系人重写器。 通过手动运行重写器,或者(通常)通过 Visual Studio 项目属性启用它,您将在编译和重写的二进制文件中保留Contract.Requires(...)
代码。 您知道代码可以工作,并且忽略 Resharper 警告,您可以运行它并进行测试。那么问题出在哪里呢? Resharper 不知道代码合约正在运行,因为它们实际上只在(后)编译时注入。 在 Resharper 看来,它的禁用方式与
DEBUG
预处理器符号的工作方式以及 Visual Studio 如何将不属于已编译二进制文件的代码区域变灰的方式相同。根据 Code Contracts 用户手册(第 2 章,第一段)和
ContractExtensions.cs
中的源代码(包含在 Code Contracts 安装文件夹中),在编译之前需要设置CONTRACTS_FULL
。 合同方法实际上是通过实现的
[ConditionalAttribute("CONTRACTS_FULL")]
并被忽略(不在编译时包含),除非设置了该标志。 Resharper 尊重此标志,并假定除非设置了该标志,否则该函数不会运行。解决方案:将条件编译符号
CONTRACTS_FULL
添加到您的项目中。 请参阅 使用代码合同 Visual Studio 和 Resharper(由 Henning Krause 编写)。(来源:infinitec.de)
Resharper 团队已收到通知; 代码分析不考虑“代码合同”项目属性选项卡上的设置,< a href="https://youtrack.jetbrains.com/issue/RSRP-190566" rel="nofollow noreferrer">支持 Microsoft 代码合同。
TL;DR - Add the conditional compilation symbol
CONTRACTS_FULL
to your project.The
Contract.Requires(...)
method is empty and disabled, unless you enable and use the Code Contacts rewriter. By running the rewriter manually, or (usually) enabling it through the Visual Studio project properties, you will keep theContract.Requires(...)
code in your compiled and rewritten binaries. You know the code will work, and ignoring the Resharper warning, you can run it and test.What is the problem then? Resharper doesn't know that the code contracts are running, since they are really only injected at (post-)compile time. In the eyes of Resharper, it's disabled in the same way as the
DEBUG
preprocessor symbol works and how Visual Studio greys out areas of your code that won't be part of your compiled binaries.According to the Code Contracts user manual (chapter 2, first paragraph) and the source code in
ContractExtensions.cs
(included in the Code Contracts install folder),CONTRACTS_FULL
needs to be set before compiling with it. The Contract methods are actually implemented with[ConditionalAttribute("CONTRACTS_FULL")]
and ignored (not included at compile time) unless the flag is set. Resharper respects this flag, and assumes that the function will not run unless it's set.Solution: Add the conditional compilation symbol
CONTRACTS_FULL
to your project. See Using Code Contracts Visual Studio and with Resharper by Henning Krause.(source: infinitec.de)
The Resharper team has been notified; Code analysis doesn't consider settings on the 'Code Contracts' project properties tab, Support of Microsoft Code Contracts.
注意:从当前的 R# 8.0 EAP 开始,包含此功能。
以下是当前(即 .NET 4.0)版本的代码契约的解决方案:
在
...\ExternalAnnotations\mscorlib\Contracts.xml
内,添加以下内容:Note: as of the current R# 8.0 EAP, this functionality is included.
Here's the solution for the current (i.e. .NET 4.0) version of Code Contracts:
Inside
...\ExternalAnnotations\mscorlib\Contracts.xml
, add the following: