Подтвердить что ты не робот

Есть ли какая-либо польза для реализации IDisposable для классов, у которых нет ресурсов?

В С#, если класс, такой как класс менеджера, не имеет ресурсов, есть ли какая-либо польза от него : IDisposable?

Простой пример:

public interface IBoxManager
{
 int addBox(Box b);
}

public class BoxManager : IBoxManager
{
 public int addBox(Box b)
 {
  using(dataContext db = new dataContext()){
   db.Boxes.add(b);
   db.SaveChanges();
  }
  return b.id;
 }
}

Будет ли какая-либо польза в использовании памяти при использовании BoxManager, если она также реализует IDisposable? public class BoxManager : IBoxManager , IDisposable

Например:

BoxManager bm = new BoxManager();
bm.add(myBox);
bm.dispose();//is there benefit to doing this?
4b9b3361

Ответ 1

Есть только две причины для реализации IDisposable для типа

  • Тип содержит собственные ресурсы, которые должны быть освобождены, когда тип больше не используется
  • Тип содержит поля типа IDisposable

Если ни одно из них не является истинным, не выполняйте IDisposable

EDIT

Несколько человек отметили, что IDisposable - отличный способ реализовать операции начала/конца или книги. Хотя это не оригинальное намерение IDisposable, оно обеспечивает очень хороший шаблон.

class Operation {
  class Helper : IDisposable {
    internal Operation Operation;
    public void Dispose() {
      Operation.EndOperation();
    }
  }
  public IDisposable BeginOperation() {
    ...
    return new Helper() { Operation = this };
  }
  private void EndOperation() {
    ...
  }
}

Примечание. Еще один интересный способ реализации этого шаблона - с помощью lambdas. Вместо того, чтобы возвращать пользователю IDisposable и надеяться, что они не забудут позвонить Dispose, им дать вам лямбда, в которой они могут выполнить операцию, и вы закрываете операцию

public void BeginOperation(Action action) {
  BeginOperationCore();
  try {
    action();
  } finally {
    EndOperation();
  }
}

Ответ 2

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

Ответ 3

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

Очень популярный пример: в ASP.NET MVC Html.BeginForm возвращается IDisposable. При создании объект открывает тег, когда вызывается Dispose, он закрывает его. Никаких родных ресурсов не задействовано, но все же хорошее использование IDisposable.

Ответ 4

Нет, не будет никакой пользы, если вы не сделаете что-то полезное, как освобождение неуправляемых ресурсов, которые ваш класс может использовать в методе Dispose.

Ответ 5

Нет, если нет (управляемых или неуправляемых) ресурсов, нет необходимости в IDisposable.

Небольшое предостережение: некоторые люди используют IDisposable для очистки обработчиков событий или больших буферов памяти, но

  • Вы не используете эти
  • В любом случае это сомнительный шаблон.

Ответ 6

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

(*), который может быть чем угодно, где угодно; возможно даже на том же компьютере.

(**) или каким-либо образом, в котором изменяется поведение или состояние внешнего объекта

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

Чтобы разрешить случай, когда объект будет оставлен без вызова IDisposable.Dispose(), который был вызван первым, система разрешает объектам регистрировать "отказоустойчивый" метод очистки под названием Finalize(). Поскольку по какой-либо причине создателям С# не нравится термин Finalize(), язык требует использования конструкции, называемой деструктором, которая делает то же самое. Обратите внимание, что в общем случае Finalize() будет маскировать, а не решать проблемы, и может создавать проблемы самостоятельно, поэтому его следует использовать с особой осторожностью, если это вообще возможно.

"Управляемый ресурс" обычно является именем, заданным объекту, который реализует IDisposable и обычно, хотя и не всегда, реализует финализатор.

Ответ 7

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

Надеюсь, что это поможет.

Ответ 8

IDisposable также отлично, если вы хотите использовать синтаксис using () {}.

В проекте WPF с ViewModels мне захотелось временно отключить события NotifyPropertyChange от повышения. Чтобы убедиться, что другие разработчики снова активируют уведомления, я написал немного кода, чтобы написать что-то вроде:

using (this.PreventNotifyPropertyChanges()) {
    // in this block NotifyPropertyChanged won't be called when changing a property value
}

Синтаксис выглядит хорошо и легко читается. Чтобы он работал, есть немного кода для написания. Вам понадобится простой одноразовый объект и счетчик.

public class MyViewModel {
    private volatile int notifyPropertylocks = 0; // number of locks

    protected void NotifyPropertyChanged(string propertyName) {
        if (this.notifyPropertylocks == 0) { // check the counter
            this.NotifyPropertyChanged(...);
        }
    }

    protected IDisposable PreventNotifyPropertyChanges() {
        return new PropertyChangeLock(this);
    }

    public class PropertyChangeLock : IDisposable {
        MyViewModel vm;

        // creating this object will increment the lock counter
        public PropertyChangeLock(MyViewModel vm) {
            this.vm = vm;
            this.vm.notifyPropertylocks += 1;
        }

        // disposing this object will decrement the lock counter
        public void Dispose() {
            if (this.vm != null) {
                this.vm.notifyPropertylocks -= 1;
                this.vm = null;
            }
        }
    }
}

Здесь нет ресурсов. Мне нужен чистый код с синтаксисом try/finally. Ключевое слово using выглядит лучше.

Ответ 9

Есть ли какая-либо польза от его использования: IDisposable?

В вашем конкретном примере это выглядит не так, однако: есть одна хорошая причина для реализации IDisposable, даже если у вас нет каких-либо полей IDisposable: ваши потомки могут.

Это одна из больших архитектурных проблем IDisposable, выделенная в IDisposable: то, что ваша мать никогда не рассказывала вам об освобождении ресурсов. В принципе, если ваш класс не запечатан, вам нужно решить, могут ли ваши потомки иметь IDisposable участников. И это не то, что вы можете реально предсказать.

Итак, если у ваших потомков, вероятно, есть члены IDisposable, это может быть хорошей причиной для реализации IDisposable в базовом классе.

Ответ 10

Короткий ответ - нет. Однако вы можете разумно использовать характер выполнения Dispose() в конце жизненного цикла объекта. Один из них уже дал хороший пример MVC (Html.BeginForm)

Я хотел бы указать на один важный аспект утверждения IDisposable и using() {}. В конце инструкции Using Dispose() метод автоматически вызывается при использовании контекстного объекта (он должен реализовывать интерфейс IDisposable, конечно).

Ответ 11

Там есть еще одна причина, о которой никто не упоминал (хотя она дебатировала, если она действительно того стоит): Конфликт говорит, что если кто-то использует класс, реализующий IDisposable, он должен вызвать свой метод Dispose (явно или через оператор 'using'). Но что произойдет, если V1 класса (в вашем общедоступном API) не нуждается в IDisposable, но V2 делает? Технически он не нарушает обратную совместимость, чтобы добавить интерфейс к классу, но из-за этой констатации это так! Поскольку старые клиенты вашего кода не будут вызывать свой метод Dispose и могут привести к тому, что ресурсы не будут освобождены. Единственный способ избежать этого - реализовать IDisposable в любом случае, если вы подозреваете, что он вам понадобится в будущем, чтобы ваши клиенты всегда вызывали ваш метод Dispose, что когда-нибудь может быть действительно необходимо. Другой (и, вероятно, лучший) способ - реализовать шаблон лямбды, упомянутый JaredPar выше в V2 API.