Вопрос

Это то, что я понимаю об IDisposable и финализаторах из "CLR через C #", "Effective C #" и других ресурсов:

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

Хотя я понимаю доводы в пользу всего вышесказанного и согласен с ними, есть один сценарий, в котором, я думаю, имеет смысл нарушить эти правила:одноэлементный класс, который отвечает за неуправляемые ресурсы (например, предоставление единой точки доступа к определенным файлам).

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

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

Является ли это разумным подходом?Если нет, то почему нет и каковы наилучшие альтернативы?

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

Другими словами, вы можете создавать сценарии, в которых для одиночек логично иметь IDisposable .

Пока ваш финализатор не вызывает методы (такие как Dispose) для любых других управляемых объектов, все должно быть в порядке.Просто помните, что порядок завершения не является детерминированным.То есть, если ваш одноэлементный объект Foo содержит ссылку на object Bar, который требует удаления, вы не сможете надежно записать:

~Foo()
{
    Bar.Dispose();
}

Сборщик мусора, возможно, уже собрал Bar.

Рискуя наступить в кучу ОО - слизи (т.е.начиная войну), одной из альтернатив использованию синглтона является использование статического класса.

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

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

Применимость Синглтона к любой конкретной ситуации в стороне,

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

Если вы хотите создать синглтон с финализатором, вам, вероятно, следует использовать статическую ссылку на него как WeakReference .Это потребует немного дополнительной работы для обеспечения потокобезопасности в средстве доступа, но это позволит собирать мусор из синглтона, когда его никто не использует (если кто-то впоследствии вызовет метод getInstance(), он получит новый экземпляр).Если бы использовалась статическая строгая ссылка, это поддерживало бы работоспособность экземпляра singleton, даже если бы на него не было других ссылок.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top