KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Базы данных » Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю

Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Троелсен Эндрю, "Язык программирования C#9 и платформа .NET5" бесплатно, без регистрации.
Перейти на страницу:

{

  ...

  .try

  {

  ...

  }  // end .try

  finally

  {

    IL_0018: callvirt instance void

      [System.Runtime]System.IDisposable::Dispose()

    ...

  }  // end handler

  IL_001f: ret

} // end of method Program::UsingDeclaration

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

Создание финализируемых и освобождаемых типов

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

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

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

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

Ниже представлена очередная версия класса

MyResourceWrapper
, который теперь является финализируемым и освобождаемым; она определена в проекте консольного приложения C# по имени
FinalizableDisposableClass
:

using System;

namespace FinalizableDisposableClass

{

  // Усовершенствованная оболочка для ресурсов.

  public class MyResourceWrapper : IDisposable

  {

    // Сборщик мусора будет вызывать этот метод, если

    // пользователь объекта забыл вызвать Dispose().

    ~MyResourceWrapper()

    {

     // Очистить любые внутренние неуправляемые ресурсы.

     // **Не** вызывать Dispose() на управляемых объектах.

    }

    // Пользователь объекта будет вызывать этот метод

    // для как можно более скорой очистки ресурсов.

    public void Dispose()

    {

      // Очистить неуправляемые ресурсы.

      // Вызвать Dispose() для других освобождаемых объектов,

      // содержащихся внутри.

      // Если пользователь вызвал Dispose(), то финализация

      // не нужна, поэтому подавить ее.

      GC.SuppressFinalize(this);

    }

  }

}

Обратите внимание, что метод

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

Формализованный шаблон освобождения

Текущая реализация класса

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

Во-вторых, желательно удостовериться в том, что метод

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

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

MyResourceWrapper
, в которой применяется официальный шаблон:

class MyResourceWrapper : IDisposable

{

  // Используется для выяснения, вызывался ли метод Dispose().

  private bool disposed = false;

  public void Dispose()

  {

    // Вызвать вспомогательный метод.

    // Указание true означает, что очистку

    // запустил пользователь объекта.

    CleanUp(true);

    // Подавить финализацию.

    GC.SuppressFinalize(this);

  }

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*