2015-10-12 17 views
6

Si consideri il seguente IDisposable classe:Utilizzando invariante per IDisposable

class MyClass : IDisposable 
{ 
    public bool IsDisposed { get; private set; } = false; 

    public void Dispose() 
    { 
     IsDisposed = true; 
    } 
} 

Ogni metodo in questa classe, tra cui Dispose(), dovrebbe iniziare con un assegno del genere:

if (IsDisposed) 
{ 
    throw new ObjectDisposedException(...); 
} 

Dal momento che è noioso e ripetitivo per scrivere questo in tutti i metodi, vorrei utilizzare l'invarianza di contratto:

public class MyClass : IDisposable 
{ 
    ... 

    [ContractInvariantMethod] 
    private void objectInvariant() 
    { 
     Contract.Invariant(!IsDisposed) 
    } 

    ... 
} 

Tuttavia, ciò garantisce che IsDisposed sia false alla fine di ogni metodo pubblico, escluso Dispose().

volta Dispose() si chiama, il controllo dovrebbe essere fatto all'inizio di ciascun metodo (compresi Dispose()). Altrimenti l'obejct sarà in uno stato non valido durante l'esecuzione del metodo, portando potenzialmente a bug difficili.

Quindi gli invarianti di contratto non sono realmente utilizzabili per IDisposable. O mi sta sfuggendo qualcosa?

È possibile forzare gli invarianti ad essere utilizzati anche come precondizioni o devo davvero scrivere lo stesso presupposto (!IsDisposed) a tutti i metodi manualmente?

+4

"Ogni metodo in questa classe, incluso Dispose(), dovrebbe iniziare con un controllo come questo" - Il metodo Dispose dovrebbe generalmente essere chiamato più volte senza lanci, quindi non dovrebbe contenere questo controllo. Inoltre, è comune eseguire questo controllo solo nei membri che non possono essere utilizzati dopo che l'oggetto è stato eliminato: gli altri membri non hanno bisogno del controllo. – Joe

+0

Guarda anche questa domanda. Penso che possa essere utile. http://stackoverflow.com/questions/9192709/run-a-method-before-all-methods-of-a-class question riguarda come chiamare un metodo prima di chiamare anymethod in quella classe. e probabilmente questa risposta http://stackoverflow.com/a/9192747/4767498 –

risposta

4

Sembra che tu abbia frainteso le invarianti. Dalla documentazione:

invarianti oggetti sono condizioni che devono essere vere per ogni istanza di una classe ogni volta che oggetto è visibile a un client.

(enfasi mia) vostro oggetto può benissimo essere visibile ad un cliente dopo aver chiamato Dispose, rendendo l'oggetto "non valido". Ma in realtà è uno stato valido per il tuo oggetto per avere IsDisposed == true.

Sei davvero alla ricerca di pre-condizioni.

+0

vedo. Sono fondamentalmente alla ricerca di un modo per evitare di porre la stessa precondizione a fondamentalmente ogni singolo metodo e proprietà. – Libor

+1

Questo sarebbe un compito per una libreria AOP come PostSharp. È anche possibile creare un intercettore dinamico usando LinFu. –

Problemi correlati