2011-01-28 5 views
6

Tengo patrón de adaptador (envoltura) sobre la clase de puerto serie. ¿Debo implementar el patrón IDisposable y llamar a _wrappedSerialPort.Dispose() en él? Hay mi clase, ¿es correcto?¿SerialPort está en recurso no administrado de .NET? Es mi clase envuelta correcta?

public class SerialPortAdapter : ISerialPortAdapter 
{ 
    private bool _disposed; 

    public event SerialDataReceivedEventHandler DataReceived; 

    private readonly SerialPort _wrappedSerialPort; 

    public SerialPort WrappedSerialPort 
    { 
     get { return _wrappedSerialPort; } 
    } 

    public string PortName 
    { 
     get { return _wrappedSerialPort.PortName; } 
     set { _wrappedSerialPort.PortName = value; } 
    } 

    public BaudRate BaudRate 
    { 
     get { return (BaudRate)Enum.ToObject(typeof(BaudRate), _wrappedSerialPort.BaudRate); } 
     set { _wrappedSerialPort.BaudRate = (int)value; } 
    } 

    public bool IsOpen 
    { 
     get { return WrappedSerialPort.IsOpen; } 
    } 

    public SerialPortAdapter(SerialPort serialPort) 
    { 
     _wrappedSerialPort = serialPort; 
     _wrappedSerialPort.DataReceived += SerialPortDataReceived; 
    } 

    public void OpenPort() 
    { 
     if (!_disposed) 
     { 
      if (!WrappedSerialPort.IsOpen) 
      { 

       WrappedSerialPort.Open(); 

      } 
     } 
    } 


    public void ClosePort() 
    { 
     if (!_disposed) 
     { 
      if (WrappedSerialPort.IsOpen) 
      { 

       WrappedSerialPort.Close(); 

      } 
     } 
    } 


    public void WriteLine(string request) 
    { 
    ... 
    } 


    public void Write(byte[] request) 
    { 
     .... 
    } 


    public byte[] Read() 
    { 
     .... 
    } 


    public string ReadLine() 
    { 
     ... 
    } 


    private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
     if (DataReceived != null) 
     { 
      DataReceived(this, e); 
     } 
    } 

    #region IDisposable Members 

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

    private void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      if (disposing) 
      { 
       // Dispose managed resources. 

      } 
      // Dispose unmanaged resources. 

      ClosePort(); 
      WrappedSerialPort.DataReceived -= SerialPortDataReceived; 
      _wrappedSerialPort.Dispose(); 

      _disposed = true; 

     } 
    } 

    ~SerialPortAdapter() 
    { 

     Dispose(false); 
    } 

    #endregion 
} 

Editar: ¿Es necesario llamar a esto, o es suficiente para llamar solamente _wrappedSerialPort.Dispose() ;?

 ClosePort(); 
     WrappedSerialPort.DataReceived -= SerialPortDataReceived; 
     _wrappedSerialPort.Dispose(); 

Respuesta

5

La respuesta de Henk Holterman es correcta: SerialPort es un recurso administrado, que posee un recurso no administrado y por lo tanto implementa IDisposable.

Dado que su contenedor posee un SerialPort, indirectamente posee el recurso no administrado de SerialPort y, por lo tanto, debe implementar IDisposable. Su implementación es incorrecta, la instancia de SerialPort de propiedad solo debe eliminarse si disposing es verdadero, ya que es un recurso administrado.

Debe ser implementado de la siguiente manera:

private void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      if (disposing) 
      { 
       // Dispose managed resources. 
       ClosePort(); 
       WrappedSerialPort.DataReceived -= SerialPortDataReceived; 
       _wrappedSerialPort.Dispose(); 
      } 
      _disposed = true; 
     } 
    } 

Además, como señala Henk Holterman, sólo es necesario un destructor si directamente recursos no administrados propios, que no es el caso aquí, y se puede simplifique la implementación IDisposable al deshacerse del destructor.

+0

Esta es la corrección correcta, no había mirado Dispose() lo suficientemente cerca. –

1
  • Sí, la olla de serie es un informe no administrado. ¿O alguna vez viste un recolector de basura para el HARDWARE FÍSICO? ;)

  • Esto se muestra en la clase para el acceso de implementación IDisposable - lo que significa que su clase que aloja un referment a largo plazo pertty mucho TIENE QUE IMPLEMENTAR IDISPOSABLE, TAMBIÉN.

+0

¿Mi clase envuelta es la correcta? – Simon

+0

Me pregunto si debo llamar al cerrar, luego anular el registro del evento y luego eliminarlo en el método Dispose. ¿Debería ser suficiente llamar solo para deshacerse? ¿Qué hay de los eventos? – Simon

+0

El puerto serie es un recurso no administrado, pero la clase SerialPort es un recurso administrado. – Joe

0

Sí, tiene razón al implementar un método Dispose en este caso. Asegúrese de agregar IDisposable a su declaración de clase. Esto hace posible el uso de la muy práctico using construcción, así:

using (var port = new SerialPortAdapter(serialPort)) { 
    port.OpenPort(); 
    // use port 
} 

una llamada a Dispose en el puerto serie envuelta debería ser suficiente, ya que esto va a cerrar el puerto. De acuerdo con la documentación de MS, Close llamará internamente al Dispose. Sin embargo, no es dañino aclarar sus intenciones al llamar explícitamente al Close.

Anular el registro del evento, como lo hace, es una buena práctica.

http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.close.aspx

6

El SerialPort sí es el propietario de un recurso no administrado y es por eso que implementa el patrón desechable completa.

En su clase, el _wrappedSerialPort es un recurso administrado. Mi definición: un recurso administrado es un recurso indirecto no administrado.

Su clase tiene no necesita el patrón completo. Podría y debería omitir el destructor (o el finalizador), ~SerialPortAdapter() y luego puede omitir el SupressFinalize.

Lo mejor sería dejar el resto, pero verás que sería más fácil acortar el código mucho más (porque void Dispose(bool) nunca se llamará con).

Cuestiones relacionadas