Разумно ли избегать явных вызовов Dispose ()? - PullRequest
9 голосов
/ 17 января 2012

Разумно ли создавать правило против явного вызова Dispose() для объекта IDisposable?

. Есть ли случаи, когда оператор using не может должным образом обеспечить очистку объекта IDisposable

Ответы [ 6 ]

11 голосов
/ 17 января 2012

Разумно ли создавать правило против явного вызова Dispose() для IDisposable объекта?

номер

Есть ли случаи, когда оператор using не может правильно обеспечить очистку объекта IDisposable?

Конечно, есть случаи, когда нет смысла использовать using, чтобы распоряжаться объектом для вас. Например, во всех случаях, когда желаемое время жизни объекта не связано с конкретной активацией метода, содержащего оператор using.

Рассмотрим, например, одноразовый объект, который «берет на себя управление» другого одноразового объекта. «Внешний» объект вполне может быть расположен блоком using, но как «внутренний» объект, вероятно, хранящийся в частном поле внешнего объекта, должен быть расположен без явного вызова Dispose()?

5 голосов
/ 17 января 2012

В некоторых случаях просто невозможно избежать явного вызова Dispose и все еще поддерживать правильную семантику. Например, рассмотрим IDisposable объекты, которые имеют поле также типа IDisposable. Они должны использовать явный вызов Dispose для удаления поля

class Container : IDisposable {
  private readonly IDisposable _field;

  public void Dipose() {

    // Don't want a using here.
    _field.Dispose();
  }
}
3 голосов
/ 17 января 2012

Одно естественное предположение состоит в том, что вы всегда можете вызвать Dispose для объекта, и это очистит ресурсы объекта, независимо от того, в каком состоянии находится объект.

Это естественное предположение не всегда является правильным.

Пример: клиентские прокси WCF. .

Правильный способ управления временем жизни прокси-сервера выглядит следующим образом:

var serviceClient = new sandbox.SandboxServiceClient();
serviceClient.HelloWorld(name);
if(serviceClient.State == CommunicationState.Faulted)
{
    serviceClient.Abort();
}
else
{
    serviceClient.Dispose();
}

Переключение на синтаксис using приведет к небезопасному коду:

using (var serviceClient = new sandbox.SandboxServiceClient()) 
{
    serviceClient.HelloWorld(name);
}  // Here An exception will be thrown if the channel has faulted

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

2 голосов
/ 17 января 2012
Оператор

A using (который на самом деле является сокращением для try / finally с Dispose, вызываемым в блоке finally) предназначен для сценариев, когда вы приобретаете ресурс, используете его, а затем распоряжаетесь им в рамках одного и того же метода.,Если у вас нет такого линейного использования ресурса (например, его использование разбито по методам), вам придется вызвать Dispose.

1 голос
/ 17 января 2012

Я бы проголосовал против такого правила: если у вас есть объект, который вы хотите использовать несколько раз при нескольких вызовах функций, оператор using заставит избавиться от этого объекта, в следующий раз, когда вы захотите его использовать, вам придется повторная инициализация ...

1 голос
/ 17 января 2012

Если стоимость создания экземпляров одноразового типа высока (например, тип, который инкапсулирует удаленное соединение), вы можете повторно использовать экземпляры для амортизации стоимости. В этом случае using будет бесполезен, и вам придется позвонить Dispose в какой-то момент.

...