Утилизация предметов (упрощение) - PullRequest
3 голосов
/ 24 ноября 2011

Я нашел этот код в Mono повторной реализации криптографических преобразований.

Я ничего не изменял и не упрощал - так оно и есть на самом деле (есть комментарии типа // Dispose unmanaged objects, но на самом деле ничего не сделано).

Теперь - связанный с IDisposable код кажется мне излишним. Можно ли это как-то упростить / удалить полностью, не нарушая чего-то важного?

public class ToBase64Transform : ICryptoTransform
{
    private bool disposed;

    ~ToBase64Transform()
    {
        Dispose(false);
    }

    public void Clear()
    {
        Dispose(true);
    }

    void IDisposable.Dispose()
    {
        Dispose(true);
        // Finalization is now unnecessary.
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposed) return;

        if (disposing)
        {
        }

        disposed = true;
    }

Полный источник находится здесь .

Ответы [ 4 ]

4 голосов
/ 24 ноября 2011

Несколько баллов:

  • Публичный API, который Mono выставляет , должен совпадать с предоставленным Microsoft, иначе все сломается.Это включает финализаторы (даже если они не нужны Mono).Mono обычно реализует больше вещей в управляемом коде, чем Microsoft (на самом деле очень часто в криптографии);

  • Тип не sealed, поэтому метод Dispose(bool) должен вызывается (например, из финализатора) или abstract, поэтому интерфейс IDisposable должен быть реализован;

  • Mono поставляется с обширным набором модульные тесты .Когда что-то выглядит странно , это хорошая идея, чтобы посмотреть на них.Соответствующая реализация MS не всегда проста, и документация MSDN (хотя и хорошая и часто обновляемая) не является достаточно редкой или полностью полной / правильной.

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

4 голосов
/ 24 ноября 2011

Если это оборачивает неуправляемые компоненты, то это наиболее подходящая реализация.

Если нет никаких неуправляемых компонентов, и оно не будет разделено на подклассы, тогда да; вы можете удалить финализатор и сделать его просто простым Dispose():

public sealed class ToBase64Transform : ICryptoTransform
{
    private bool disposed;

    public void Dispose()
    {
        if (disposed) return;
        // Dispose managed objects
        disposed = true;
    }

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

Я не уверен, что ожидал бы, что метод «Clear ()» вызовет «Dispose ()», но, возможно, это является нормой в контексте криптопотоков.

3 голосов
/ 24 ноября 2011

Это совершенно стандартный способ реализации IDisposable. Согласитесь, никакой работы не сделано, но если она должна быть там для совместимости с MS.Net, то лучше всего сделать правильно.

1 голос
/ 28 ноября 2011

Класс, который наследует от базы, которая реализует IDisposable, обычно должен гарантировать, что вызов IDisposable.Dispose будет вызывать логику распоряжения базового класса, а также свою собственную.Для этого необходимо, чтобы было применено хотя бы одно из двух условий:

  1. Должны быть некоторые средства, с помощью которых производный класс может запросить, чтобы логика Dispose производного класса вызывалась из реализации базового класса IDisposable..Dispose (), без необходимости повторной реализации IDisposable.Dispose ().
  2. Если производный класс повторно реализует IDisposable.Dispose, должны быть какие-то средства, с помощью которых базовый класс может представить свою собственную удаленную логику производному классу, чтобы подпрограмма IDisposable.Dispose производного класса могла вызвать его.

Существует ряд способов, по которым хотя бы одно из этих условий может быть выполнено;в разных ситуациях разные методы могут быть оптимальными.В частности, для классов, имеющих открытый метод Dispose (), который будет семантически идентичен методу IDisposable.Dispose (), было бы проще всего просто иметь базовый класс открытым виртуальным методом Dispose (), который неявно реализует IDisposable.Dispose.Если производный класс переопределяет этот метод, он переопределяет поведение IDisposable.Dispose, но его Dispose () может вызывать base.Dispose () для активации логики удаления родительского объекта.Однако у этого подхода есть один недостаток: некоторые классы могут не захотеть иметь открытый метод Dispose (), который семантически идентичен IDisposable.Dispose ().Хотя было бы целесообразно использовать этот подход для классов, где он подходит, и какой-то другой подход для других классов, Microsoft решила, что было бы лучше иметь общий подход для всех классов.

Идея состоит в том, чтовсе наследуемые классы, которые реализуют IDisposable, будут иметь защищенный виртуальный метод, сигнатура которого не соответствует общедоступному «void Dispose ()»;IDisposable.Dispose () будет вызывать этот метод (со значением параметра True) для всей его логики удаления, а производный класс, который переопределяет этот метод, может вызывать базовую логику удаления, вызывая соответствующий метод его родителя.Хотя Microsoft допустила возможность метода «Завершить», вызывающего этот метод со значением false, на самом деле в этом нет никакой необходимости. Добавление метода Finalize (или деструктора C #) к классу, который не включает в себя все условия, требуемые для одного, включая вызовы GC.KeepAlive () в ключевых местах), может привести к поломкеизменение, которое вызывает незначительные ошибки. Если класс должен использовать неуправляемые ресурсы, но родительский класс этого не делает, это следует обработать, определив новые финализируемые классы для инкапсуляции неуправляемых ресурсов в управляемые объекты, а затем унаследованный класс будет содержать теуправляемые объекты.

...