2015-07-20 27 views
5

Lavoro su un enorme progetto in C# .NET 4.0. Esiste una classe personalizzata ereditata dalla classe System.Net.Sockets.SocketAsyncEventArgs. Qualcosa di simile a quanto segue:Come implementare l'interfaccia IDisposable in una classe ereditata da SocketAsyncEventArgs

public class SocketTaskArgs : SocketAsyncEventArgs 
{ 
    public SocketTaskArgs() 
    { 
     Completed += someEventhHandler; 
    } 

    public void CleanUp() 
    { 
     Completed -= someEventhHandler; 
    } 

    /* 
     There is a lot of code here that is unimportant at the moment. 
    */ 
} 

Così, ho voluto spostare il contenuto del metodo di cleanup() per smaltire il metodo (bool).

Come prima cosa, ho controllato il codice sorgente della classe base - SocketAsyncEventArgs (utilizzando Vai a definizione in modo che i metadati siano stati visualizzati come origine). Ho scoperto che questa classe implementa l'interfaccia IDisposable. Bello, ho solo bisogno di sovrascrivere il metodo Dispose (bool), no? (Vedere IDisposable Interface on MSDN, la sezione "IDisposable e gerarchia ereditarietà", per ulteriori dettagli). Niente di nuovo per me ... Purtroppo, la classe SocketAsyncEventArgs è implementato come seguendo:

public class SocketAsyncEventArgs : EventArgs, IDisposable 
{ 
    public void Dispose(); 

    //some other stuff here 
} 

Ciò significa che, non c'è modo come ignorare Dispose (bool) metodo, come è implementato come privato invece di protetto ... Qual è la ragione di questo?

Successivamente, ho letto il metodo SocketAsyncEventArgs.Dispose() su MSDN. La cosa divertente è che, contiene la seguente sezione:

Note per gli eredi

Smaltire possono essere chiamati più volte da altri oggetti. Quando si esegue l'override di Dispose (Boolean), fare attenzione a non fare riferimento agli oggetti che sono stati precedentemente smaltiti in una precedente chiamata a Dispose. Per ulteriori informazioni su come implementare Dispose (Boolean), , vedere Implementazione di un metodo di smaltimento.

Aspetta ... cosa?

Quando si esegue l'override Dispose (Boolean), ...

Come faccio a ignorare Dispose (Boolean)?

Qual è il modo consigliato di implementare l'interfaccia IDisposable in questo caso?

+1

Non è privato, non è implementato affatto (consultare http://referencesource.microsoft.com/System/net/System/Net/Sockets/Socket.cs.html#8877). Usa un finalizzatore ma sembra che non sia stato realmente implementato nel modello raccomandato. –

+0

Sembra che 'Dispose' sia pubblico, ma non' virtuale'. –

+0

Non si dovrebbe ereditare da quella classe. Probabilmente non puoi cambiarlo facilmente in un grande progetto esistente. – usr

risposta

3

Non sembra essere nulla ti impedisce di attuare IDisposable sulla vostra classe figlia, prendere questo esempio:

public class DisposableParent : IDisposable 
{ 
    public void Dispose() 
    { 
     Console.WriteLine("The parent was disposed."); 
    } 
} 

public class DisposableChild : DisposableParent, IDisposable 
{ 
    public new void Dispose() 
    { 
     base.Dispose(); 
     Console.WriteLine("The child was disposed."); 
    } 
} 

public class Program 
{ 
    public static void Main() 
    { 
     using (DisposableChild c = new DisposableChild()) { } 
     Console.ReadKey(true); 
    } 
} 

ha pronunciato la seguente uscita:

Il genitore è stato smaltito.

Il bambino è stato eliminato.

Il compilatore avverte di nascondere lo Smaltire la classe padre nel bambino, in modo da utilizzare l'operatore new si libera di questo avvertimento, basta assicurarsi di chiamare la classe di base Dispose dalla classe bambino (e la sua attuazione il giusta direzione).

Il dispose per il bambino sarebbe diventato qualcosa di simile:

public class DisposableChild : DisposableParent, IDisposable 
{ 
    private bool _disposed = false; 

    public new void Dispose() 
    { 
     Dispose(true); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      if (!_disposed) 
      { 
       base.Dispose(); 
       Console.WriteLine("The child was disposed."); 
       _disposed = true; 
      } 
     } 
    } 
} 

E sì, questo funziona ancora se fai qualcosa di simile:

using (DisposableParent p = new DisposableChild()) 
{ 

} 

Ma qualcosa di simile può romperlo:

public class Program 
{ 
    public static void Main() 
    { 
     DisposableChild c = new DisposableChild(); 
     DisposeOfIt(c); 

     Console.ReadKey(true); 
    } 

    public static void DisposeOfIt(DisposableParent p) 
    { 
     p.Dispose(); 
    } 
} 

Stampa solo che il genitore è stato eliminato. Quindi, se hai usato questo metodo, dovresti stare attento a controllare la durata dei tuoi oggetti.

+0

Grazie per la risposta. Sono d'accordo con te, che posso implementare un'interfaccia IDisposable sulla mia classe ereditata. Questa è stata la prima cosa che mi è venuta in mente. Sono solo curioso di sapere se qualcuno verrà con un'altra e forse un'idea migliore. Se non c'è niente di meglio nel prossimo futuro, segnerò la tua risposta come accettata. –