ReSharper - Null Assegnazione quando si utilizza Microsoft.Contratti
-
06-09-2019 - |
Domanda
C'è un modo per indicare a ReSharper che un riferimento null non si verificano a causa di Design-da-Contratto Richiede il controllo?Per esempio, il codice riportato di seguito si alza il messaggio di avviso (Possible 'null' assignment to entity marked with 'NotNull' attribute
) in ReSharper linee 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);
}
La cosa davvero strana è che se si rimuove il Contract.Requires(...)
linea, il ReSharper messaggio va via.
Aggiornamento
Ho trovato la soluzione attraverso ExternalAnnotations che è stato menzionato anche da Mike di seguito.Ecco un esempio di come fare una funzione in Microsoft.Contratti:
- Creare una directory chiamata
Microsoft.Contracts
sotto ilExternalAnnotations
ReSharper directory. - Successivamente, Creare un file denominato
Microsoft.Contracts.xml
e popolare, in questo modo:
<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>
- Riavviare Visual Studio, e il messaggio va via!
Soluzione
Nota:come l'attuale R# 8.0 EAP, questa funzionalità è inclusa.
Ecco la soluzione per la corrente (es..NET 4.0) versione del Codice dei Contratti:
All'interno ...\ExternalAnnotations\mscorlib\Contracts.xml
, aggiungere il seguente:
<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>
Altri suggerimenti
Mi piacerebbe aggiungere che per le persone che scrivono i propri metodi di asserzione e simili, è possibile includere questi attributi senza un file XML esterno. In Visual Studio, visitare il ReSharper > Options > Code Annotations
e fare clic sul pulsante Copy default implementation to clipboard
. Quindi creare un nuovo file (ovunque si desidera in soluzione) e incollare il codice dagli appunti. Ora, è possibile creare metodi come questo:
public class Require
{
[AssertionMethod]
public static void That(
[AssertionCondition(AssertionConditionType.IS_TRUE)]
bool requiredCondition,
string message = null)
{
...
}
...
}
Ora, qualsiasi chiamata a Require.That(a != null)
indicherà ReSharper che non si può andare oltre questa linea se a
è nullo. A differenza della tecnica ExternalAnnotations, questo funzionerà per chiunque utilizzi i vostri metodi, senza alcun lavoro supplementare da parte loro.
Aggiornamento
ReSharper è cambiato il loro modello di annotazione del contratto a partire dalla versione 7. Ecco ciò che il metodo di cui sopra sarebbe simile ora:
public class Require
{
[ContractAnnotation("requiredCondition:false => halt")]
public static void That(
bool requiredCondition,
string message = null)
{
...
}
...
}
Penso che si può, ma non è banale. Date un'occhiata a guida in linea ReSharper per il codice di annotazione
Si annotate le classi BCL e il quadro NUnit (e non solo) per migliorare le capacità di ispezione del codice Resharpers.
Per esempio con il NUnit afferma che annotati con un'AssertionMethodAttribute. Questo dice ispezione del codice Resharpers che se hai passato un Assert.IsNotNull (foo); poi pippo non deve essere nullo e non produrrà il "possibile assegnazione 'null' ..." più di avvertimento.
Si potrebbe produrre un file XML annotare il metodo Contracts.Requires per indicare che è proprio come un'asserzione.
Il motivo per il messaggio scompare quando si rimuove l'asserzione è che R # lavora in una modalità "ottimista" per impostazione predefinita. Si presuppone tutto non è nullo fino a quando si fa qualcosa che indica in realtà può essere nullo. Ecco cosa succede quando si aggiunge la chiamata a String.IsNullOrEmpty
. Si sta affermando che s
potrebbe effettivamente essere nullo. E 'solo che non è consapevole del fatto che il metodo Contract.Requires
si fermerà l'esecuzione, se questo è il caso, ma che è risolto con l'annotazione.
In R # 5.0 è possibile passare a una modalità pessimistica che assume il peggio ad ogni angolo.
ho preso XML Porges' e le annotazioni per l'Assert aggiunto e assumono metodi. Io Wiki questa risposta nel caso in cui altre persone vogliono aggiungere ulteriori metodi.
<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 è cambiato il loro modello di annotazione del contratto a partire dalla versione 7.
È necessario un file diverso. La nuova posizione (Credo che solo per le applicazioni Metro) è: "C: \ Program Files (x86) \ JetBrains \ ReSharper \ v7.1 \ Bin \ ExternalAnnotations \ .NETCore \ System.Diagnostics.Contracts \ Contracts.xml"
Sto usando Visual Studio 2012 e .Net 4.5 e ReSharper 7.1.
Contenuto:
<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 - Aggiungere il simbolo compilazione condizionale CONTRACTS_FULL
al progetto
Il metodo Contract.Requires(...)
è vuoto e disabili, a meno che non si attiva e utilizzando questo codice Contatti masterizzatore. Eseguendo il masterizzatore manualmente, o (di solito) che consente attraverso le proprietà visive del progetto Studio, si può mantenere il codice Contract.Requires(...)
nei vostri binari compilati e riscritti. Sai che il codice funzionerà, e ignorando l'avvertimento ReSharper, è possibile eseguirlo e test.
Qual è il problema allora? ReSharper non sa che i contratti di codice sono in esecuzione, dal momento che sono in realtà solo in iniettati (post-) tempo di compilazione. Agli occhi di ReSharper, è disabilitato nello stesso modo come il simbolo DEBUG
preprocessore funziona e come di Visual Studio grigi le aree del codice che non saranno parte del tuo binari compilati.
#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
Secondo la codice contratti utente manuale (capitolo 2, primo comma) e il codice sorgente in ContractExtensions.cs
(inclusi nei contratti di codice cartella di installazione), CONTRACTS_FULL
ha bisogno di essere set prima di compilare con esso. Il Contratto metodi sono effettivamente implementati con [ConditionalAttribute("CONTRACTS_FULL")]
e ignorato (non incluso al momento della compilazione) a meno che sia impostato il flag. ReSharper rispetta questo flag, e si presuppone che la funzione non verrà eseguito meno che non sia impostato.
[ConditionalAttribute("CONTRACTS_FULL")]
public static void Requires(bool condition) { ... }
Soluzione: aggiungere il simbolo di compilazione condizionale CONTRACTS_FULL
al progetto. Vedere Utilizzando Codice Contratti Visual Studio e con ReSharper di Henning Krause.
(fonte: infinitec.de )
Il team ReSharper è stato notificato; analisi codice non prende in considerazione le impostazioni sulle 'codice dei contratti' Proprietà progetto scheda , < a href = "https://youtrack.jetbrains.com/issue/RSRP-190566" rel = "nofollow noreferrer"> Supporto dei contratti codice Microsoft .