ReSharper - Microsoft.Contracts 사용 시 Null 할당 가능
Design-by-Contract Requires 검사로 인해 null 참조가 발생하지 않을 것임을 ReSharper에 표시할 방법이 있습니까? 예를 들어 다음 코드는 Possible 'null' assignment to entity marked with 'NotNull' attribute
7행과 8행에서 ReSharper 의 경고( )를 발생 시킵니다 .
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 메시지가 사라집니다.
업데이트
아래 Mike도 언급한 ExternalAnnotations를 통해 솔루션을 찾았습니다. 다음은 Microsoft.Contracts의 함수에 대해 수행하는 방법의 예입니다.
- ReSharper 디렉토리
Microsoft.Contracts
아래에 라는 디렉토리를 만듭니다ExternalAnnotations
. - 다음으로 라는 파일을
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부터 이 기능이 포함되어 있습니다.
다음은 코드 계약의 현재(예: .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>
자신의 어설션 메서드 등을 작성하는 사람들을 위해 외부 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)
{
...
}
...
}
이제 에 대한 모든 호출 은 가 null인 Require.That(a != null)
경우 이 줄을 넘을 수 없음을 ReSharper에 나타냅니다 a
. ExternalAnnotations 기술과 달리 이것은 추가 작업 없이 귀하의 메소드를 사용하는 모든 사람에게 작동합니다.
업데이트
Resharper는 버전 7부터 계약 주석 모델을 변경했습니다. 이제 위의 방법은 다음과 같습니다.
public class Require
{
[ContractAnnotation("requiredCondition:false => halt")]
public static void That(
bool requiredCondition,
string message = null)
{
...
}
...
}
나는 당신이 할 수 있다고 생각하지만 그것은 사소한 일이 아닙니다. 코드 주석에 대한 Resharper 온라인 도움말 살펴보기
그들은 Resharpers 코드 검사 기능을 향상시키기 위해 BCL 클래스와 NUnit 프레임워크(및 그 이상)에 주석을 달았습니다.
예를 들어 NUnit은 AssertionMethodAttribute로 주석을 추가한 어설션을 사용합니다. 이것은 Assert.IsNotNull(foo); foo는 null이 아니어야 하며 "Possible 'null' assignment..." 경고가 더 이상 생성되지 않습니다.
Contracts.Requires 메서드에 주석을 추가하는 xml 파일을 생성하여 Assert와 같다는 것을 나타낼 수 있습니다.
어설션을 제거하면 메시지가 사라지는 이유는 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>
Resharper는 버전 7부터 계약 주석 모델을 변경했습니다.
다른 파일이 필요합니다. 새 위치(메트로 앱에만 해당)는 "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=>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=>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=>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=>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=>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=>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=>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=>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=>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=>halt</argument>
</attribute>
</member>
</assembly>
TL;DR - CONTRACTS_FULL
프로젝트에 조건부 컴파일 기호 를 추가합니다 .
Contract.Requires(...)
활성화 및 코드 연락처 라이터를 사용하지 않는 방법은 비어을 사용할 수 없습니다. 재작성을 수동으로 실행하거나 (일반적으로) Visual Studio 프로젝트 속성을 통해 활성화하면 Contract.Requires(...)
컴파일 및 재작성된 바이너리에 코드 가 유지됩니다 . 코드가 작동한다는 것을 알고 있으며 Resharper 경고를 무시하고 코드를 실행하고 테스트할 수 있습니다.
그렇다면 무엇이 문제인가? 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
에 따르면 코드 계약의 사용 설명서 (2 장, 첫 번째 단락)과의 소스 코드 ContractExtensions.cs
(코드 계약에 포함 된 설치 폴더) CONTRACTS_FULL
그것으로 컴파일하기 전에 설정해야합니다. 계약 방법은 실제로 구현 과 [ConditionalAttribute("CONTRACTS_FULL")]
및 플래그가 설정되어 있지 않으면 (컴파일 시간에 포함되지 않음) 무시했다. Resharper는 이 플래그를 존중하며 설정되지 않으면 함수가 실행되지 않는다고 가정합니다.
[ConditionalAttribute("CONTRACTS_FULL")]
public static void Requires(bool condition) { ... }
솔루션: CONTRACTS_FULL
프로젝트에 조건부 컴파일 기호 를 추가하십시오 . 코드 계약 사용 Visual Studio 및 Henning Krause의 Resharper 사용을 참조하세요 .
(출처: infinitec.de )
Resharper 팀이 알림을 받았습니다. 코드 분석은 '코드 계약' 프로젝트 속성 탭 , Microsoft 코드 계약 지원 에 대한 설정을 고려하지 않습니다 .
ReferenceURL : https://stackoverflow.com/questions/929859/resharper-possible-null-assignment-when-using-microsoft-contracts
'IT이야기' 카테고리의 다른 글
C#용 린트 (0) | 2021.10.22 |
---|---|
Rails의 모델에 대한 외래 키 관계 정의 (0) | 2021.10.22 |
사람들이 Spring MVC에서 XSS를 수행하는 것 방지 방법 (0) | 2021.10.22 |
libc 없이 컴파일 (0) | 2021.10.22 |
PropertyInfo가 컬렉션인지 확인하는 방법 (0) | 2021.10.21 |