Как бороться с классом, чем инкапсулирует одноразовый экземпляр? - PullRequest
5 голосов
/ 30 декабря 2010
interface IMyInterace
{
void Open();
object Read();
void Close();
}

class MyImplementation : IMyInterface
{
public void Open() { /* instantiates disposible class */ }
//...
public void Close() { /* calls .Dispose(); */ }

}

Есть ли хороший способ справиться с ситуацией такого типа, чтобы обеспечить вызов одноразовых экземпляров внутри класса? (Нет никаких сигналов для вызывающих, что они должны вызывать 'Close', кроме как в документации.) Реализации IMyInterface не обязательно инкапсулируют экземпляры IDisposible и закрываются и открываются повторно в течение всего времени жизни приложения.

Я думаю сделать это:

  • Реализация ID, доступного в MyImplementation.
  • Установите Dispose () для вызова Close ().
  • Добавить вызов метода Close () или Dispose () для начало Open для обеспечения предыдущего звонок был закрыт.

Пользователи IMyInterface не знают, какую реализацию они используют, поэтому я не уверен, какую ценность имеет создание одноразового использования MyImplementation, и опять же, не все реализации будут инкапсулировать IDisposibles.

Ответы [ 3 ]

5 голосов
/ 30 декабря 2010

Стандартный способ справиться с этим - просто MyImplementation реализовать IDisposable.

3 голосов
/ 30 декабря 2010

Как уже упоминал Джон, ваша первая точка обозначена правильно.

Иногда метод Close() функционально является синонимом Dispose() и существует для поддержания семантической согласованности с абстракцией. То есть, чтобы дополнить метод Open(). В других случаях Close() позволит вам снова открыть, но Dispose() не должен. Таким образом, ваш второй пункт также хорош.

Точка 3 не обязательно применима, поскольку выбрасываемый объект не должен использоваться повторно. Если вам нужно снова вызвать Open(), вам нужно использовать новый экземпляр. Фактически, метод Open() должен выдавать ObjectDisposedException после вызова Dispose() (путем проверки частного логического disposed флага). Если вы хотите, чтобы объект поддерживал повторное открытие после закрытия, вы можете рассмотреть возможность использования Debug.Assert() и / или создания исключения, если Open() вызывается без Close(). Это поможет предотвратить небрежное управление этими экземплярами.

Обязательно следуйте полной схеме одноразового использования, которая более сложна, чем простая реализация интерфейса:

bool disposed;

public void Dispose() // don't make virtual!
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if(!disposed)
    {
        if(disposing) 
        {
            // dispose of managed resources here, for example:
            // if(resource != null) { resource.Dispose(); } 
        }
    }

    // dispose of unmanaged resources here 

    disposed = true;
}
1 голос
/ 30 декабря 2010

В дополнение к ответам уже здесь:

Если этот класс (часто / иногда) используется только через интерфейс, я бы посоветовал наследовать IMyInterace от IDisposable.

Это позволит вашим пользователям использовать эти объекты согласованным образом.Недостаток, конечно, в том, что вам может понадобиться добавить (фиктивные) методы Dispose к классам, которые на самом деле в этом не нуждаются.Но выгода заключается в согласованности и гибкости: что, если в будущем класс изменится, и ему понадобится Dispose ()?

Минимальный подход:

interface IMyInterace : IDisposable { }

sealed class MyImplementation : IMyInterface 
{   
   public void Open() { /* instantiates disposible class */ }

   public void Close() { /* calls _myField.Dispose(); */ }

   public void Dispose() { Close(); }  // only use this short form in a sealed class

}
...