2011-01-28 3 views
6

У меня есть шаблон адаптера (обертка) по классу последовательного порта. Должен ли я реализовать шаблон IDisposable и вызвать в нем _wrappedSerialPort.Dispose()? Есть мой класс, это правильно?Является ли SerialPort в .NET неуправляемым ресурсом? Является ли мой завернутый класс правильным?

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 
} 

Edit: Нужно ли назвать это, или достаточно, чтобы назвать только _wrappedSerialPort.Dispose() ;?

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

ответ

5

Ответы Хенка Холтермана верны: SerialPort - это управляемый ресурс, который сам владеет неуправляемым ресурсом и, следовательно, реализует IDisposable.

Поскольку ваша обертка имеет SerialPort, она косвенно владеет неуправляемым ресурсом SerialPort и, следовательно, должна реализовать IDisposable. Ваша реализация неверна, принадлежащий экземпляр SerialPort должен быть удален, только если disposing является истинным, поскольку он является управляемым ресурсом.

Он должен быть реализован следующим образом:

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

Кроме того, как Хенк Хольтерман указывает, что вам нужно только деструктор, если вы непосредственно собственные неуправляемые ресурсы, которые не так здесь, и вы можете упростить реализацию IDisposable, избавившись от деструктора.

+0

Это правильная коррекция, я не смотрел на Dispose() достаточно близко. –

1
  • Да, серийный банк неуправляемый отчет. Или вы когда-нибудь видели сборщик мусора для ФИЗИЧЕСКОЙ ОБОРУДОВАНИЯ? ;)

  • Это показано классом для доступа к реализации IDisposable - что означает, что ваш класс, на котором размещен долгосрочный термин refernce pertty, очень ДОЛЖЕН ВЫПОЛНЯТЬ ИДЕНТИФИКАЦИЮ, СЛИШКОМ.

+0

Итак, мой завернутый класс правильный? – Simon

+0

Я задаюсь вопросом, следует ли мне позвонить близко, затем отменить регистрацию события и затем утилизировать в методе Dispose. Должно быть достаточно, чтобы вызывать только распоряжаться? Как насчет событий? – Simon

+0

Последовательный порт является неуправляемым ресурсом, но класс SerialPort является управляемым ресурсом. – Joe

0

Да, вы в этом уверены в правильности реализации метода Dispose. Обязательно добавьте IDisposable к декларации вашего класса. Это дает возможность использовать очень удобный using конструкцию, как это:

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

Вызов Dispose на обернутой последовательного порта должно быть достаточно, так как это приведет к закрытию порта. Согласно документации MS, Close вызовет Dispose внутренне. Тем не менее, нет никакого вреда в том, чтобы быть ясным в ваших намерениях, явно называя Close.

Незарегистрированный от мероприятия, как и вы, является хорошей практикой.

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

6

Сам SerialPort является владельцем неуправляемого ресурса, и именно поэтому он реализует полный Одноразовая узор.

В вашем классе _wrappedSerialPort является ресурс. Мое определение: a управляемый ресурс является косвенным неуправляемый ресурс.

Ваш класс не нужен полный шаблон. Вы можете и должны опустить деструктор (или финализатор), ~SerialPortAdapter() и после этого вы можете пропустить SupressFinalize.

Лучше всего оставить все остальное, но вы увидите, что будет легко сократить код намного больше (потому что void Dispose(bool) никогда не будет вызван с false).