Является ли SerialPort в .NET неуправляемым ресурсом?Является ли мой завернутый класс правильным? - PullRequest
7 голосов
/ 28 января 2011

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

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
}

Редактировать: это необходимо для вызова или достаточно вызывать только _wrappedSerialPort.Dispose ();?

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

Ответы [ 4 ]

6 голосов
/ 28 января 2011

Сам SerialPort является владельцем неуправляемого ресурса, поэтому он реализует шаблон full Disposable.

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

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

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

5 голосов
/ 28 января 2011

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

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

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

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

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

1 голос
/ 28 января 2011

Да, вы правы в реализации метода 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

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

  • Это показано классом для доступа, реализующим IDisposable - это означает, что ваш класс, в котором размещается долгая ссылка, очень важен, ДОЛЖЕН ОСУЩЕСТВЛЯТЬ IDISPOSABLE, ТОО.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...