Проясните некоторые вещи об интерфейсе IDisposable. Экземпляр (должен быть) равен нулю после вызова Dispose? - PullRequest
0 голосов
/ 06 сентября 2010

У меня есть класс, который реализует интерфейс IDisposable.

using System;

class A : IDisposable
{
        public void Dispose()
        {
            Stop(); // some actions to stop internal threads

            this = null;
        }
}

Почему я не могу присвоить this = null в методе Dispose?Я знаю, что это доступно только для чтения.

Например:

A a = new A();
a.Run();
// ...
a.Dispose();
// i want in this line a = null

Я думал, что метод IDisposable и Dispose гарантируют, что экземпляр класса A будет равен нулю после вызова Dispose (),Но это не правда.

Ответы [ 4 ]

3 голосов
/ 06 сентября 2010

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

Обратите внимание, что объект не обязательно можно использовать после его утилизации.Например, удаление MemoryStream не очищает данные в памяти - использование ToArray для него впоследствии все равно будет работать.

Действительно, документация для IDisposableявно говорит о возможности его использования для сброса объекта для повторного использования:

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

2 голосов
/ 06 сентября 2010

Просто чтобы добавить к тому, что уже было сказано:

Важно понимать, что есть объекты , и есть ссылки (переменные), и это не одно и то же .

Когда вы пишете var a = new object();, вы делаете две вещи:

  1. Создание нового экземпляра object. Этот экземпляр не имеет «имени» - просто место в памяти. Что есть, то есть. Но для того, чтобы у нас было что назвать, давайте назовем это «Боб».
  2. Объявление переменной a, которая ссылается на object только что созданного.

Теперь, когда вы пишете a = null;, вы делаете ничего Бобу. Вы изменяете a на ссылку вместо Боба, null, или, другими словами, «нет объекта». Таким образом, вы больше не можете получить доступ к «Бобу», используя a.

Значит ли это, что Боба не существует? Нет. Боб все еще там, где он был.

Подумайте об этом (в основном это сценарий, упомянутый Хенком ):

var a = new object(); // Again, we're calling this object Bob.
object b = a;

Теперь b - это еще одна переменная , такая же, как a. И так же, как a, b ссылается на Боба. Но опять же, как и с a, запись b = null; ничего не делает для Боба. Он просто меняет b, так что больше не указывает на объект.

Вот куда я иду с этим. Похоже, у вас сложилось впечатление, что вы делаете это:

a.Dispose();

... как-то так и сделал:

a = null;

... что было как-то эквивалентно этому:

Bob= null; // nowBobis no object?

Но если бы это было так, то b (выше) теперь будет указывать на без объекта , даже если для него никогда не было установлено значение null!

В любом случае, из моего объяснения выше, надеюсь, ясно, что это просто не то, как работает CLR. Как отметил Джон, интерфейс IDisposable на самом деле не связан с освобождением памяти. Речь идет об освобождении общих ресурсов. Он не - не может - удалять объекты из памяти, как если бы это было так, тогда у нас было бы поведение, которое я описал выше (ссылки внезапно становятся недействительными из ниоткуда).

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

1 голос
/ 06 сентября 2010

Ваше предположение неверно.Dispose() не восстанавливает экземпляр и не влияет на ссылку.

Это служебный метод, который получает особое внимание от фреймворка / компилятора, который позволяет вам легко очищать ресурсы, не обрабатываемые GC.Кроме этого это просто обычный метод.Вызов метода не должен влиять на саму ссылку.

Рекомендация для реализации Dispose() специально гласит

Чтобы обеспечить правильную очистку ресурсов, метод Dispose должен вызыватьсянесколько раз без исключения.

1 голос
/ 06 сентября 2010

Это невозможно, но и бесполезно.

Рассмотрим b в:

A b = a; // alias
a.Dispose();
// i want in this line a = null

И это не проблема, есть объект, на который ссылаются a и b. Просто его внутреннее состояние изменилось на «закрыто». Некоторые классы IDisposable имеют член bool IsDisposed, который можно безопасно вызывать после Dispose()

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