sto cercando di capire come i contratti di codice .NET interagiscono con la parola chiave lock
, utilizzando il seguente esempio:Code Contracts avvertono di "assicura non provata" quando le serrature sono coinvolti
public class TestClass
{
private object o1 = new object();
private object o2 = new object();
private void Test()
{
Contract.Requires(this.o1 != null);
Contract.Requires(this.o2 != null);
Contract.Ensures(this.o1 != null);
lock (this.o2) {
this.o1 = new object();
}
}
}
Quando eseguo lo strumento di analisi statica Codice contratto, esso stampa avvertimento aa: Ensures unproven: this.o1 != null
Se faccio qualsiasi:
- cambiamento del
o2
nellock
ao1
, - modifica la
o1
all'interno dellock
bloccoo2
, - aggiungendo una seconda linea all'interno del blocco
lock
assegnando unnew
object
pero2
- cambiamento
lock (this.o2)
aif (this.o2 != null)
, - rimuovere la Dichiarazione
lock
interamente.
l'avviso scompare.
Tuttavia, cambiando la linea all'interno del lock
blocco var temp = new object();
(eliminando in tal modo tutti i riferimenti al o1
dal metodo) provoca ancora l'avvertimento:
private void Test()
{
Contract.Requires(this.o1 != null);
Contract.Requires(this.o2 != null);
Contract.Ensures(this.o1 != null);
lock (this.o2) {
var temp = new object();
}
}
Quindi ci sono due domande:
- Perché si verifica questo avviso?
- Cosa si può fare per prevenirlo (tenendo presente che questo è un esempio di giocattolo e ci sono effettivamente cose che accadono all'interno dello
lock
nel codice reale)?
Apparentemente i Contratti di codice non considerano l'istanziazione di 'o1' che si verifica automaticamente durante l'esecuzione del costruttore come prova sufficiente che garantisce o1! = Null.Assures è una post-condizione, e il 'lock 'implica che il metodo sarà chiamato da più thread. –
@RobertHarvey Ma come ho detto, se si cambia 'this.o1 = new object()' in 'this.o2 = new object()', va bene. Non può garantire nulla in quel caso che non possa essere assicurato anche nel caso originale, e coinvolge comunque un blocco. E il 'Requires' dovrebbe essere una prova sufficiente del fatto che' o1' non è nullo all'inizio del metodo. –