Правильное использование интерфейса IDisposable

Имеется дружественный к Android порт javamail , который вы должны использовать. В вашем приложении должны быть три библиотеки: mail.jar, activation.jar и addnal.jar (sic). Похоже, что у вас отсутствует то, от чего зависит библиотека активации, и это может быть связано с тем, что вы не используете порт Android этой библиотеки.

Я успешно использовал версию javamail для Android в проект, и он работает очень хорошо.

1536
задан Elanis 10 April 2019 в 12:12
поделиться

11 ответов

Точка Располагает, должен освободить неуправляемые ресурсы. Это должно быть сделано в какой-то момент, иначе они никогда не будут очищаться. Сборщик "мусора" не знает, как звонить DeleteHandle() на переменной типа IntPtr, это не знает, должно ли это звонить DeleteHandle().

Примечание: Что такое неуправляемый ресурс? Если Вы нашли его в Microsoft.NET Framework: этим управляют. Если Вы пошли, введя по абсолютному адресу вокруг MSDN сами, это неуправляемо. Что-либо Вы использовали вызовы P/Invoke для выбираний наружу хорошего удобного мира всего доступного Вам в Платформе.NET, неуправляемо – и Вы теперь ответственны за чистку его.

Объект, что Вы создали потребности выставить некоторый метод, что внешний мир может звонить для чистки неуправляемых ресурсов. Метод можно назвать тем, что Вы любите:

public void Cleanup()

или

public void Shutdown()

Но вместо этого существует стандартизированное название этого метода:

public void Dispose()

Был даже созданный интерфейс, IDisposable, это имеет просто что один метод:

public interface IDisposable
{
   void Dispose()
}

Таким образом, Вы заставляете свой объект выставить IDisposable интерфейс и тот способ, которым Вы обещаете, что записали что отдельный метод очистить Ваши неуправляемые ресурсы:

public void Dispose()
{
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
}

И Вы сделаны. Кроме Вас может добиться большего успеха.


Что, если Ваш объект выделил Систему 250 МБ. Рисование. Битовый массив (т.е..NET управляемый Растровый класс) как своего рода кадровый буфер? Несомненно, это - управляемый объект.NET, и сборщик "мусора" освободит его. Но Вы действительно хотите оставить 250 МБ памяти, просто находящейся там – ожидающий сборщика "мусора" для возможного прихода, и освобождаете его? Что, если существует открытое соединение с базой данных? Конечно, мы не хотим то соединение, находящееся открытый, ожидая GC для завершения объекта.

Если пользователь звонил Dispose() (значение они больше не планируют использовать объект) почему бы не избавиться от тех расточительных битовых массивов и соединений с базой данных?

Таким образом, теперь мы будем:

  • избавьтесь от неуправляемых ресурсов (потому что мы имеем к), и
  • избавьтесь от управляемых ресурсов (потому что мы хотим быть услужливыми),

Поэтому давайте обновим наш Dispose() метод для избавлений от тех управляемых объектов:

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose();
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose();
      this.frameBufferImage = null;
   }
}

И все хорошо, кроме Вас может добиться большего успеха!


Что, если человек забыл звонить Dispose() на Вашем объекте? Затем они пропустили бы некоторые неуправляемые ресурсы!

Примечание: Они не пропустят управляемые ресурсы, потому что в конечном счете сборщик "мусора" собирается работать на фоновом потоке, и освободить память, связанную с любыми неиспользуемыми объектами. Это будет включать Ваш объект и любые управляемые объекты, которые Вы используете (например, Bitmap и DbConnection).

Если человек забыл звонить Dispose(), мы можем все еще убраться подобру-поздорову! У нас все еще есть способ назвать его для них: когда сборщик "мусора" наконец находит время для освобождения (т.е. завершение) наш объект.

Примечание: Сборщик "мусора" в конечном счете освободит все управляемые объекты. Когда это делает, это звонит Finalize метод на объекте. GC не знает, или уход, о Вашем Располагать метод. Это было просто именем, которое мы выбрали для метода, который мы называем, когда мы хотим избавиться от неуправляемого материала.

Разрушение нашего объекта Сборщиком "мусора" является идеальным временем для освобождения тех противных неуправляемых ресурсов. Мы делаем это путем переопределения Finalize() метод.

Примечание: В C# Вы явно не переопределяете Finalize() метод. Вы пишете метод, который похож на деструктор C++, и компилятор берет это, чтобы быть Вашей реализацией Finalize() метод:

~MyObject()
{
    //we're being finalized (i.e. destroyed), call Dispose in case the user forgot to
    Dispose(); //<--Warning: subtle bug! Keep reading!
}

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

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.gdiCursorBitmapStreamFileHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose(); //<-- crash, GC already destroyed it
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose(); //<-- crash, GC already destroyed it
      this.frameBufferImage = null;
   }
}

Таким образом, то, в чем Вы нуждаетесь, является путем к Finalize() сказать Dispose() то, что это не должно касаться никаких управляемых ресурсов (потому что они не могли бы быть там больше), при тихом освобождении неуправляемых ресурсов.

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

Этому внутреннему методу можно было дать некоторое произвольное имя как "CoreDispose" или "MyInternalDispose", но является традицией для вызова его Dispose(Boolean):

protected void Dispose(Boolean disposing)

Но более полезное название параметра могло бы быть:

protected void Dispose(Boolean itIsSafeToAlsoFreeManagedObjects)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too, but only if I'm being called from Dispose
   //(If I'm being called from Finalize then the objects might not exist
   //anymore
   if (itIsSafeToAlsoFreeManagedObjects)  
   {    
      if (this.databaseConnection != null)
      {
         this.databaseConnection.Dispose();
         this.databaseConnection = null;
      }
      if (this.frameBufferImage != null)
      {
         this.frameBufferImage.Dispose();
         this.frameBufferImage = null;
      }
   }
}

И Вы изменяете свою реализацию IDisposable.Dispose() метод к:

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
}

и Ваш финализатор к:

~MyObject()
{
   Dispose(false); //I am *not* calling you from Dispose, it's *not* safe
}

Примечание: Если Ваш объект убывает от объекта, который реализует Dispose, затем не забывайте звонить, их основа Располагают метод, когда Вы переопределяете, Расположите:

public override void Dispose()
{
    try
    {
        Dispose(true); //true: safe to free managed resources
    }
    finally
    {
        base.Dispose();
    }
}

И все хорошо, кроме Вас может добиться большего успеха!


Если вызовы пользователя Dispose() на Вашем объекте затем все было очищено. Позже, когда сборщик "мусора" приходит, и вызовы Завершают, он будет затем звонить Dispose снова.

Мало того, что это расточительно, но и если Ваш объект имеет ссылки спама на объекты, Вы уже избавились от последней возможности до Dispose(), Вы попытаетесь расположить их снова!

Вы заметите в моем коде, я старался удалить ссылки на объекты, которые я расположил, таким образом, я не пытаюсь звонить Dispose на ссылке на объект спама. Но это не мешало тонкой ошибке закрасться.

Когда вызовы пользователя Dispose(): дескриптор CursorFileBitmapIconServiceHandle уничтожается. Позже, когда сборщик "мусора" работает, он попытается уничтожить тот же дескриптор снова.

protected void Dispose(Boolean iAmBeingCalledFromDisposeAndNotFinalize)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle); //<--double destroy 
   ...
}

Путем Вы фиксируете, это, говорят сборщику "мусора", что он не должен потрудиться завершать объект – его ресурсы были уже очищены, и больше работы не необходимо. Вы делаете это путем вызова GC.SuppressFinalize() в Dispose() метод:

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
   GC.SuppressFinalize(this); //Hey, GC: don't bother calling finalize later
}

Теперь, когда пользователь звонил Dispose(), мы имеем:

  • освобожденные неуправляемые ресурсы
  • освобожденные управляемые ресурсы

Нет никакого смысла в GC, выполняющем финализатор – все заботилось о.

Не мог я использовать Завершить к неуправляемым ресурсам очистки?

Документация для Object.Finalize говорит:

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

Но в документации MSDN также говорится, для IDisposable.Dispose:

Выполняет определенные приложением задачи, связанные с освобождением, выпуском или сбросом неуправляемых ресурсов.

Таким образом, который является этим? Какой является местом для меня к неуправляемым ресурсам очистки? Ответ:

Это - Ваш выбор! Но выберите Dispose.

Вы, конечно, могли поместить свою неуправляемую очистку в финализатор:

~MyObject()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //A C# destructor automatically calls the destructor of its base class.
}

Проблема с этим - Вы, понятия не имеют, когда сборщик "мусора" найдет время для завершения Вашего объекта. Ваши неуправляемые, ненужные, неиспользованные собственные ресурсы будут слоняться поблизости, пока сборщик "мусора" в конечном счете не работает. Затем это назовет Ваш метод финализатора; чистка неуправляемых ресурсов. Документация Объекта. Завершите указывает на это:

Точное время, когда финализатор выполняется, не определено. Для обеспечения детерминированного выпуска ресурсов для экземпляров класса реализуйте Близкий метод или обеспечьте a IDisposable.Dispose реализация.

Это - достоинство использования Dispose к неуправляемым ресурсам очистки; Вы узнаете, и управление, когда неуправляемый ресурс очищен. Их разрушение "детерминировано".


Отвечать на Ваш исходный вопрос: Почему бы не освобождать память теперь, а не для того, когда GC решает сделать это? У меня есть программное обеспечение распознавания лиц, которое должно избавиться от 530 МБ внутренних изображений теперь, так как они больше не необходимы. Когда мы не делаем: машина стачивается к останову свопинга.

Бонусное чтение

Для любого, кому нравится стиль этого ответа (объяснение, почему, таким образом, как становится очевидным), я предполагаю, что Вы читаете Главу Один из Существенных COM Don Box:

На 35 страницах он объясняет проблемы использования двоичных объектов и изобретает COM на Ваших глазах. После того как Вы понимаете, почему из COM, остающиеся 300 страниц очевидны, и просто детализируют реализацию Microsoft.

Я думаю каждый программист, который когда-либо имел дело с объектами, или COM должен, по крайней мере, прочитать первую главу. Это - лучшее объяснение чего-либо когда-либо.

Дополнительное бонусное чтение

Когда все, что Вы знаете, неправильно Eric Lippert

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

2519
ответ дан 22 November 2019 в 20:13
поделиться

Существуют вещи, которые Dispose() операция делает в примере кода, который мог бы иметь эффект, который не произошел бы из-за нормального GC эти MyCollection объект.

, Если объекты, на которые ссылаются _theList или _theDict, будут упомянуты другими объектами, то тот List<> или Dictionary<> объект не подвергнется набору, но не будет внезапно иметь никакого содержания. Если бы было, не Располагают () операцию как в примере, те наборы все еще содержали бы свое содержание.

, Конечно, если бы это было ситуацией, я назвал бы ее поврежденным дизайном - я просто указываю (педантично, я предполагаю), что Dispose() операция не могла бы быть абсолютно избыточной, в зависимости от того, существует ли другое использование List<> или Dictionary<>, которые не показывают во фрагменте.

2
ответ дан Michael Burr 10 April 2019 в 22:12
поделиться

Цель Расположить шаблона состоит в том, чтобы обеспечить механизм для чистки и управляемых и неуправляемых ресурсов и когда это происходит, зависит от того, как Расположить метод называют. В Вашем примере использование Располагает, на самом деле не делает ничего связанного для расположения, начиная с очистки списка не оказывает влияния на тот располагаемый набор. Аналогично, вызовы для установки переменных в NULL также не оказывают влияния на GC.

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

public class SimpleCleanup : IDisposable
{
    // some fields that require cleanup
    private SafeHandle handle;
    private bool disposed = false; // to detect redundant calls

    public SimpleCleanup()
    {
        this.handle = /*...*/;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                if (handle != null)
                {
                    handle.Dispose();
                }
            }

            // Dispose unmanaged managed resources.

            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

методом, который является самым важным здесь, является Расположение (bool), который на самом деле работает при двух различных обстоятельствах:

  • расположение == верный: метод назвал прямо или косвенно код пользователя. Могут быть расположены управляемые и неуправляемые ресурсы.
  • расположение == ложь: метод назвало время выполнения из финализатора, и Вы не должны ссылаться на другие объекты. Только неуправляемые ресурсы могут быть расположены.

проблема с простым разрешением GC заботиться о выполнении очистки состоит в том, что Вы не имеете никакого реального контроля, когда GC выполнит цикл сбора (можно назвать GC.Collect (), но Вы действительно не были должны), таким образом, ресурсы могут остаться вокруг дольше, чем необходимый. Помните, вызов Располагают (), на самом деле не вызывает цикл сбора или всегда заставляет GC собираться/освобождать объект; это просто обеспечивает средства для более детерминировано очистки используемые ресурсы, и скажите GC, что эта очистка была уже выполнена.

смысл IDisposable и расположить шаблона не о непосредственном освобождении памяти. Единственное время вызов для Расположения будет на самом деле даже иметь шанс непосредственного освобождения памяти, - когда это обрабатывает расположение == ложный сценарий и управление неуправляемыми ресурсами. Для управляемого кода не будет на самом деле исправлена память, пока GC не выполняет цикл сбора, который Вы действительно не имеете никакого контроля над (кроме вызова GC.Collect (), который я уже упомянул, не хорошая идея).

Ваш сценарий не действительно действителен, так как строки в.NET не используют unamanged ресурсов и не реализуют IDisposable, нет никакого способа вынудить их быть "очищенными".

39
ответ дан Scott Dorman 10 April 2019 в 22:12
поделиться

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

Ответ на Ваше редактирование: Вид. Если я делаю это:

public void WasteMemory()
{
    var instance = new MyCollection(); // this one has no Dispose() method
    instance.FillItWithAMillionStrings();
}

// 1 million strings are in memory, but marked for reclamation by the GC

Это функционально идентично этому в целях управления памятью:

public void WasteMemory()
{
    var instance = new MyCollection(); // this one has your Dispose()
    instance.FillItWithAMillionStrings();
    instance.Dispose();
}

// 1 million strings are in memory, but marked for reclamation by the GC

, Если действительно действительно действительно необходимо освободить память это очень мгновенное, звоните GC.Collect(). Нет никакой причины сделать это здесь, все же. Память будет освобождена, когда она будет необходима.

11
ответ дан mqp 10 April 2019 в 22:12
поделиться

Если MyCollection будет, собрал "мусор" так или иначе, то Вы не должны должны быть располагать его. Выполнение так просто взболтает более, чем необходимый ЦП, и может даже делать недействительным некоторый предрасчетный анализ, который уже выполнил сборщик "мусора".

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

РЕДАКТИРОВАНИЕ В ответ на комментарий Scott:

единственное время, метрики производительности GC затронуты, - когда вызов [так] GC.Collect () сделан"

Концептуально, GC поддерживает представление графика ссылки на объект и все ссылки на него от стековых фреймов потоков. Эта "куча" может быть довольно большой и охватить много страниц памяти. Как оптимизация, GC кэширует свой анализ страниц, которые вряд ли изменятся очень часто для предотвращения повторного сканирования страница излишне. GC получает уведомление от ядра, когда данные на странице изменяются, таким образом, это знает, что страница грязна и требует пересканирования. Если набор находится в Gen0 затем, вероятно, что другие вещи на странице изменяются также, но это менее вероятно Gen1 и Gen2. Анекдотическим образом эти рычаги не были доступны в Mac OS X для команды, которая портировала GC к Mac для получения плагина Silverlight, работающего над той платформой.

Другая точка против ненужного избавления от ресурсов: вообразите ситуацию, где процесс разгружается. Предположите также, что процесс работал в течение некоторого времени. Возможности состоят в том, что многие из страниц памяти того процесса были подкачаны к диску. По крайней мере они больше не находятся в L1 или кэше L2. В такой ситуации нет никакого смысла для приложения, которое это разгружает для свопинга всех тех страниц данных и кодовых страниц назад в память для 'высвобождения' средств, которые будут выпущенными операционной системой так или иначе, когда процесс завершается. Это относится к управляемым и даже определенным неуправляемым ресурсам. Только ресурсы, которые поддерживают нефоновые потоки, должны быть расположены, иначе процесс останется живым.

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

платформа.NET использует эти IDisposable интерфейс как сигнал, даже предупреждение, разработчикам, что этот класс должен быть расположенным. Я не могу думать ни о каких типах в платформе, которые реализуют IDisposable (исключая явные интерфейсные реализации), где распоряжение является дополнительным.

11
ответ дан Drew Noakes 10 April 2019 в 22:12
поделиться

IDisposable часто используется, чтобы использовать using оператор и использовать в своих интересах простой способ сделать детерминированную очистку управляемых объектов.

public class LoggingContext : IDisposable {
    public Finicky(string name) {
        Log.Write("Entering Log Context {0}", name);
        Log.Indent();
    }
    public void Dispose() {
        Log.Outdent();
    }

    public static void Main() {
        Log.Write("Some initial stuff.");
        try {
            using(new LoggingContext()) {
                Log.Write("Some stuff inside the context.");
                throw new Exception();
            }
        } catch {
            Log.Write("Man, that was a heavy exception caught from inside a child logging context!");
        } finally {
            Log.Write("Some final stuff.");
        }
    }
}
58
ответ дан yfeldblum 10 April 2019 в 22:12
поделиться

В любом случае я ожидал бы, что код будет меньше эффективен, пропуская его.

Вызов Ясного () методы являются ненужными, и GC, вероятно, не сделал бы этого, если бы Расположение не сделало этого...

4
ответ дан Arjan Einbu 10 April 2019 в 22:12
поделиться

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

<час>

Руководство по проектированию Платформы является инструкциями и не правилами. Они говорят Вам, для чего интерфейс, прежде всего, когда использовать его, как использовать его, и если не использовать его.

я когда-то прочитал код, который был простым RollBack () при отказе, использующем IDisposable. Класс MiniTx ниже начал бы работу, флаг Располагают () и если бы эти Commit вызова никогда не происходило, то он затем звонил бы Rollback на себе. Это добавило слой косвенности, делающей код вызова, намного легче понять и поддержать. Результат смотрел что-то как:

using( MiniTx tx = new MiniTx() )
{
    // code that might not work.

    tx.Commit();
} 

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

using( LogTimer log = new LogTimer("MyCategory", "Some message") )
{
    // code to time...
}

, Таким образом, вот несколько конкретных примеров, которые не делают никакой очистки неуправляемого ресурса, но делают успешно используемый IDisposable для создания более чистого кода.

6
ответ дан Robert Paulson 10 April 2019 в 22:12
поделиться

Я не повторю обычный материал об Использовании или освобождении неуправляемых ресурсов, который был все покрыт. Но я хотел бы указать на то, что кажется распространенным заблуждением.
, Учитывая следующий код

Public Class LargeStuff
  Implements IDisposable
  Private _Large as string()

  'Some strange code that means _Large now contains several million long strings.

  Public Sub Dispose() Implements IDisposable.Dispose
    _Large=Nothing
  End Sub

я понимаю, что Доступная реализация не следует текущим инструкциям, но надо надеяться Вы все получаете идею.
Теперь, то, когда Располагают, называют, сколько памяти освобождено?

Ответ: Ни один.
Вызов Располагает, может высвободить неуправляемые средства, он не МОЖЕТ исправить управляемую память, только GC может сделать это. Но это вовсе не значит то вышеупомянутое не является хорошей идеей, после вышеупомянутого шаблона все еще хорошая идея на самом деле. Однажды Расположите, был выполнен, нет ничего останавливающего GC, исправляющий память, которая использовалась _Large, даже при том, что экземпляр LargeStuff может все еще быть в объеме. Строки в _Large могут также быть в генерале 0, но экземпляр LargeStuff мог бы быть генералом 2, поэтому снова, память будет исправлена раньше.
нет никакого смысла в добавлении финализатора для вызова Расположить метода показанным выше все же. Это просто ЗАДЕРЖИТ исправление памяти, чтобы позволить финализатору работать.

6
ответ дан pipTheGeek 10 April 2019 в 22:12
поделиться

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

Что касается общего вопроса об управляемом/неуправляемом и обсуждении в других ответах, я думаю, что любой ответ на этот вопрос должен запуститься с определения неуправляемого ресурса.

то, К чему это сводится, - то, что существует функция, которую можно вызвать для помещения системы в состояние, и существует другая функция, которую можно вызвать для возвращения его из того состояния. Теперь, в типичном примере, первый мог бы быть функцией, которая возвращает дескриптор файла, и второй мог бы быть вызовом к CloseHandle.

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

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

Взгляд на пример в вопросе Судьи. Изменения в добавлении отступа Файла журнала должны быть отлично вложены, или все это идет не так, как надо. Также они вряд ли будут ориентированы на многопотоковое исполнение.

возможно цеплять поездку со сборщиком "мусора" для очищения неуправляемых ресурсов. Но только если функции изменения состояния ориентированы на многопотоковое исполнение, и два состояния могут иметь время жизни то перекрытие всегда. Таким образом, пример Судьи ресурса не должен иметь финализатора! Это просто не помогло бы никому.

Для тех видов ресурсов, можно просто реализовать IDisposable без финализатора. Финализатор является абсолютно дополнительным - это должно быть. Это приукрашено или даже не упомянуто во многих книгах.

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

недостающая часть - то, что необходимо вручную записать, Располагают и заставляют его звонить на поля и базовый класс. C++ / программисты CLI не должен делать этого. Компилятор пишет это для них в большинстве случаев.

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

Вместо того, чтобы писать класс, Вы пишете функцию. Функция принимает, что делегат перезванивает к:

public static void Indented(this Log log, Action action)
{
    log.Indent();
    try
    {
        action();
    }
    finally
    {
        log.Outdent();
    }
}

И затем простой пример был бы:

Log.Write("Message at the top");
Log.Indented(() =>
{
    Log.Write("And this is indented");

    Log.Indented(() =>
    {
        Log.Write("This is even more indented");
    });
});
Log.Write("Back at the outermost level again");

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

Эта техника менее полезна, если ресурс является видом, который может иметь перекрывающееся время жизни, потому что затем Вы хотите смочь создать ресурс A, затем ресурс B, затем уничтожить ресурс A и затем позже уничтожить ресурс B. Вы не можете сделать этого при принуждении пользователя к отлично вложенному множеству как это. Но затем необходимо использовать IDisposable (но все еще без финализатора, если Вы не реализовали threadsafety, который не свободен).

17
ответ дан Daniel Earwicker 10 April 2019 в 22:12
поделиться

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

идиома, которую я использую для реализации IDisposable ( не ориентированный на многопотоковое исполнение ):

class MyClass : IDisposable {
    // ...

    #region IDisposable Members and Helpers
    private bool disposed = false;

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing) {
        if (!this.disposed) {
            if (disposing) {
                // cleanup code goes here
            }
            disposed = true;
        }
    }

    ~MyClass() {
        Dispose(false);
    }
    #endregion
}
14
ответ дан Jake1164 10 April 2019 в 22:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: