2015-08-26 12 views
5

In un paio di punti, le persone hanno suggerito di utilizzare private void Dispose(bool) per il modello IDisposable. Ciò sembra superato (almeno per le classi non sigillate), poiché il nuovo modello suggerito (secondo Microsoft) è protected virtual void Dispose(bool).vuoto privato Dispose (bool)?

Il fatto è che Code Analysis non segnala private void Dispose(bool) per violazione di CA1063, anche se sembra violare direttamente il modello.

Che succede? ? È private void Dispose(bool) in qualche modo sempre chiamato (o compilato a qualcosa che assomiglia a protected virtual Dispose(bool)

Se questo è qualche problema con analisi del codice ed è il modello corretto, ci sono modi per rilevare questo Possibilmente con StyleCop

Edit??: dopo considerazione, è che una classe base può chiamare base.Dispose() che ha colpito private void Dispose(bool) Anche se non è in grado di passare in un argomento

Edit:? Esempio

public class A : IDisposable 
{ 
    ~A() 
    { 
     this.Dispose(false); 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private void Dispose(bool disposing) // Should be protected virtual void Dispose(bool) 
    { 
     Console.WriteLine("A"); 
    } 
} 

public class B : A 
{ 
    protected virtual void Dispose(bool disposing) // Proper pattern. 
    { 
     Console.WriteLine("B"); 
    } 
} 

public static class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(); 
     a.Dispose(); // Prints "A" 

     B b = new B(); 
     b.Dispose(); // Prints "A"! 
    } 
} 

Come potete vedere da questo, rende l'uso del modello di smaltimento totalmente ingombrante.

È possibile aggirare questo un po 'nascondendo il public void Dispose(void) e quindi chiamando base.Dispose() da qualche parte. Questo funziona quindi "simile" al modello di smaltimento corretto quando si chiama B b = new B(); b.dispose();eccetto quando si chiama A b = new B(); b.Dispose();, che chiama solo il metodo DisposeA.

public class B : A 
{ 
    public void Dispose() // Causes CA error with or without "new". 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) // Proper pattern. 
    { 
     base.Dispose(); // Writes "A" (without quotes). 
     Console.WriteLine("B"); 
    } 
} 

Fondamentalmente, questa faccenda sembra terribile. Sappiamo se è un bug che CA accetta private void Dispose(bool) e c'è un modo per lanciare un avvertimento almeno con StyleCop?

Edit: Non penso che dovrei accettare la risposta di Alexandre, in quanto relativa alla domanda che ho sostanzialmente si riduce a "Potrebbe essere un bug", insieme a qualcosa che dovrebbe essere un commento. Se qualcun altro ha qualcosa di più decisivo, penso che sarebbe una risposta più appropriata.

+0

E le lezioni sigillate? Protetto dovrebbe essere utilizzato per le classi aperte, private per sealed. –

+0

Funziona per entrambi è il problema. Abbiamo trovato un paio di posti in cui le classi non sigillate non stavano gettando il problema. Ciò ha un senso, però, che il privato è richiesto per le classi sigillate. Tuttavia, sarebbe bello che la CA si lanci se la classe non è sigillata (e dovrebbe anche saperlo). Penso che la mia modifica mostri perché potrebbe non essere completamente fuori dal bosco perché non si possa lanciare, ma è comunque un po 'fastidioso. –

+0

Chiamare 'base.Dispose()' sarebbe una chiara violazione del pattern, quindi non penso che lo spieghi. Sono d'accordo con il tuo pensiero originale che l'analisi del codice dovrebbe riportare il caso che hai presentato. – sstan

risposta

6

Implementing a Dispose Method

Il IDisposable interfaccia richiede l'attuazione di un singolo metodo senza parametri, smaltire. Tuttavia , il modello dispose richiededue metodi Dispose attuare:

  • Un pubblico non virtuale (NonInheritable in Visual Basic) IDisposable.Dispose attuazione che non ha parametri.
  • Un metodo Dispose virtuale (Overridable in Visual Basic).

Perché il pubblico, non virtuale (NonInheritable in Visual Basic), metodo Dispose senza parametri viene chiamato da un consumatore di tipo, il suo scopo è quello di liberare risorse non gestite e per indicare che il finalizzatore, se uno è presente, non deve correre. A causa di questo, ha un'implementazione standard:

public void Dispose() 
{ 
    // Dispose of unmanaged resources. 
    Dispose (true); 
    // Suppress finalization. 
    GC.SuppressFinalize (this); 
} 

Nella seconda sovraccarico, il parametro disponendo è un booleano che indica se la chiamata metodo proviene da un metodo Dispose (il suo valore è true) o da una finalizzatore (il suo valore è falso).

Quando il garbage collector decide che l'oggetto non è più necessario, si cercherà di finalizzare in caso si è dimenticato di chiamare il metodo senza parametri dispose, perché se avete fatto e si sta seguendo il modello, la chiamata sarebbe soppresso.

See: How Finalization Works

privato vs virtuali protetti:

è necessario utilizzare sempre virtuali protetti come la documentazione dice che se vi capitasse di voler sostenere sottoclassi che segue correttamente il modello.

Perché alcune persone usano la versione privata? Forse perché l'eredità non è mai stata la loro intenzione, specialmente se stai solo generando metodi al volo usando strumenti come Resharper, il più delle volte questi metodi diventeranno privati.

Perché l'analisi del codice non segnala il problema?

Potrebbe essere un bug. Fornire un piccolo campione che fornisce il problema in modo che altre persone possano testare sulle proprie macchine.

+0

Aggiungi ed alcuni campioni. –

+0

Che cosa dovrebbe fare Dispose (bool) quando la bool è vera e falsa? – AksharRoop

+0

Alla fine della pagina (https://msdn.microsoft.com/en-us/library/system.object.finalize.aspx) vedrai un esempio, Se true, devi disporre di tutte le risorse, perché tu chiamato il metodo di smaltimento e desidera recuperare tutta la memoria utilizzata. Se falso, significa che il garbage collector sta eliminando l'oggetto, quindi è necessario disporre solo delle risorse non gestite (oggetti creati al di fuori dell'applicazione C#), il resto degli oggetti può essere lasciato intatto mentre il garbage collector eliminerà li quando è necessario. –

Problemi correlati