ReSharper - Possível Null Atribuição ao usar Microsoft.Contracts
-
06-09-2019 - |
Pergunta
Existe alguma maneira para indicar ao ReSharper que uma referência nula não irá ocorrer por causa de Design-by-contrato exige a verificação? Por exemplo, o seguinte código vai aumentar o aviso (Possible 'null' assignment to entity marked with 'NotNull' attribute
) em ReSharper em linhas 7 e 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);
}
O que é realmente estranho é que, se você remover a linha Contract.Requires(...)
, a mensagem ReSharper vai embora.
Atualizar
Eu encontrei a solução através ExternalAnnotations que também foi mencionado por Mike abaixo. Aqui está um exemplo de como fazê-lo para uma função em Microsoft.Contracts:
- Crie um diretório chamado
Microsoft.Contracts
sob o diretórioExternalAnnotations
ReSharper. - Em seguida, crie um arquivo chamado
Microsoft.Contracts.xml
e preencher assim:
<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>
- Reinicie o Visual Studio, ea mensagem vai embora!
Solução
Nota ??strong>:. A partir da corrente de R # 8,0 EAP, esta funcionalidade está incluído
Aqui está a solução para o atual (ou seja, .NET 4.0) versão de contratos de código:
Dentro ...\ExternalAnnotations\mscorlib\Contracts.xml
, adicione o seguinte:
<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>
Outras dicas
Eu gostaria de acrescentar que para as pessoas escrevendo seus próprios métodos de asserção e tal, você pode incluir esses atributos sem um arquivo XML externo. Em Visual Studio, vá para ReSharper > Options > Code Annotations
e clique no botão Copy default implementation to clipboard
. Em seguida, crie um novo arquivo (em qualquer lugar que você quer em sua solução) e cole no código da área de transferência. Agora, você pode criar métodos como este:
public class Require
{
[AssertionMethod]
public static void That(
[AssertionCondition(AssertionConditionType.IS_TRUE)]
bool requiredCondition,
string message = null)
{
...
}
...
}
Agora, qualquer chamada para Require.That(a != null)
indicará para ReSharper que você não pode passar por esta linha se a
é nulo. Ao contrário da técnica ExternalAnnotations, isso vai funcionar para qualquer um usando seus métodos, sem nenhum trabalho adicional da sua parte.
Atualização
ReSharper mudou seu modelo de anotação do contrato a partir da versão 7. Aqui está o que o método acima seria parecido com agora:
public class Require
{
[ContractAnnotation("requiredCondition:false => halt")]
public static void That(
bool requiredCondition,
string message = null)
{
...
}
...
}
Eu acho que você pode, mas não é trivial. Dê uma olhada na ReSharper ajuda on-line para o código de anotação
Eles anotado as classes BCL eo quadro NUnit (e mais) para melhorar as capacidades de inspeção de código Resharpers.
Por exemplo, com o NUnit afirma que anotada com um AssertionMethodAttribute. Isto diz inspeção de código Resharpers que se você tem passado um Assert.IsNotNull (foo); em seguida, foo não deve ser nula e não produzirá a "atribuição Possível 'null' ..." aviso mais.
Você pode produzir um arquivo xml anotando o método Contracts.Requires para indicar que ele é como um Assert.
A razão a mensagem desaparece quando você remove a afirmação é que R # funciona em um modo "otimista" por padrão. Assume-se que tudo é não nulo até que você faça algo que indica que ele pode realmente ser nulo. Isso é o que acontece quando você adiciona a chamada para String.IsNullOrEmpty
. Você está afirmando que s
realmente pode ser nulo. Ele só não está ciente de que o método Contract.Requires
irá parar a execução se esse é o caso, mas que você resolvido com a anotação.
Em R # 5.0 você pode mudar para um modo pessimista que assume o pior em cada esquina.
Eu levei XML Porges' e anotações adicionadas para a Assert e assumir métodos. Vou wiki esta resposta no caso de outras pessoas querem adicionar mais métodos.
<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 mudou seu modelo de anotação do contrato a partir da versão 7.
Você precisa de um arquivo diferente. O novo local (acho que apenas para aplicações Metro) é: "C: \ Program Files (x86) \ JetBrains \ ReSharper \ v7.1 \ Bin \ ExternalAnnotations \ .NETCore \ System.Diagnostics.Contracts \ Contracts.xml"
Estou usando o Visual Studio 2012 e .Net 4.5 e ReSharper 7.1.
Conteúdo:
<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. - Adicione o símbolo de compilação condicional CONTRACTS_FULL
ao seu projeto
O método Contract.Requires(...)
está vazia e deficientes, a menos que você ativar e utilizar o Contactos Código banner. Ao executar o banner manualmente, ou (geralmente) permitindo que através das propriedades do projeto Visual Studio, você vai manter o código Contract.Requires(...)
em seus binários compilados e reescritos. Você sabe que o código irá funcionar, e ignorando o aviso ReSharper, você pode executá-lo e teste.
O que é o problema, então? O ReSharper não sabe que os contratos de código estão em execução, uma vez que são realmente só injetado pelo (pós-) compilação tempo. Aos olhos de ReSharper, é desativada da mesma forma como as obras símbolo DEBUG
de pré-processamento e como Visual Studio cinzas para fora áreas do seu código que não farão parte dos seus binários compilados.
#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
De acordo com o código dos contratos de usuário manual (capítulo 2, primeiro parágrafo) e o código-fonte em ContractExtensions.cs
(incluídos nos contratos de código instalar pasta), as necessidades CONTRACTS_FULL
ser definir antes de compilar com ele. O Contrato métodos são realmente implementadas com [ConditionalAttribute("CONTRACTS_FULL")]
e ignorado (não incluído em tempo de compilação) a menos que o sinalizador está definido. aspectos ReSharper esta bandeira, e assume que a função não funcionará a menos que seja definido.
[ConditionalAttribute("CONTRACTS_FULL")]
public static void Requires(bool condition) { ... }
Solução: Adicione o símbolo de compilação condicional CONTRACTS_FULL
ao seu projeto. Consulte Usando contratos de código Visual Studio e com reSharper por Henning Krause.
(fonte: infinitec.de )
A equipe ReSharper tenham sido notificados; Código análise não considera as configurações nos 'contratos de código' propriedades do projeto guia , < a href = "https://youtrack.jetbrains.com/issue/RSRP-190566" rel = "nofollow noreferrer"> Apoio de contratos de código Microsoft .