Синглтон с финализатором, но не IDisposable - PullRequest
15 голосов
/ 21 января 2009

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

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

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

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

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

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

Ответы [ 6 ]

6 голосов
/ 21 января 2009

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

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

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

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

4 голосов
/ 21 января 2009

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

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

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

4 голосов
/ 21 января 2009

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

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

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

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

2 голосов
/ 21 января 2009

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

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

0 голосов
/ 28 сентября 2010

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

0 голосов
/ 21 января 2009

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

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

...