Использование Dispose для Singleton для очистки ресурсов - PullRequest
7 голосов
/ 28 мая 2010

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

Сейчас у меня есть это удаление, обрабатываемое Cleanup() методом синглтона, который приложение вызывает при закрытии. Когда я писал документацию для Cleanup(), меня поразило, что я описывал, какой метод Dispose() следует использовать для очистки ресурсов. Изначально я не реализовал IDisposable, потому что это казалось неуместным в моем синглтоне, потому что я не хотел, чтобы что-то выбрасывало сам синглет. В настоящее время нет, но в будущем может быть причина, по которой этот Cleanup() может быть вызван, но синглтон должен будет существовать. Я думаю, что могу включить GC.SuppressFinalize(this); в метод Dispose, чтобы сделать это возможным.

Поэтому мой вопрос состоит из нескольких частей:

1) Является ли реализация IDisposable для синглтона принципиально плохой идеей?

2) Я просто смешиваю семантику здесь, имея Cleanup() вместо Dispose(), и поскольку я распоряжаюсь ресурсами, мне действительно следует использовать dispose?

3) Будет ли реализация Dispose () с GC.SuppressFinalize(this); сделать так, чтобы мой синглтон не был фактически уничтожен в случае, если я хочу, чтобы он жил после вызова очистки базы данных.

Ответы [ 3 ]

8 голосов
/ 28 мая 2010

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

Теперь вставка и удаление объекта после того, как приложение выполнено с ним, не обязательно плохая. Вы должны быть осторожны, когда звоните. Если вы действительно заинтересованы в очистке, и у вас есть только одна ссылка на нее, вы можете поместить код очистки в финализатор объектов ~YourClass таким образом, что он будет вызываться только с .Net, если он больше не нужен (когда приложение закрывается, если это настоящий синглтон).

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

Да, это просто семантика. Dispose - это стандарт, показывающий, что есть вещи, которые необходимо очистить после выполнения программы с объектом.

Будет ли реализовывать 'Dispose ()' с GC.SuppressFinalize (это); сделай это так мой синглтон на самом деле не разрушен в случае, если я хочу жить после вызов для очистки базы данных.

Нет, это означает, что когда вы вызываете метод dispose, сборщик мусора не будет вызывать пользовательский финализатор объекта.

7 голосов
/ 28 мая 2010
  1. Реализация IDisposable для синглтона может быть хорошей идеей, если вы используете технику CAS вместо блокировок для создания синглтона. Как то так.

    if (instance == null) {
        var temp = new Singleton();
        if (Interlocked.CompareExchange(ref instance, temp, null) != null) &&
                temp is IDisposable) {
            ((IDisposable)temp).Dispose();
        }
    }
    return instance
    

    Мы создали временный объект и попробовали атомарный метод Compare-and-Swap, поэтому нам нужно избавиться от этого временного объекта, если он реализует IDisposable и он не был записан в местоположение экземпляра.

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

  2. Если вы не хотите, чтобы другой код очищал или удалял ваш объект, просто не предоставляйте никакой возможности для этого. Однако может быть хорошей идеей - предоставить какой-то метод reset (), который позволит синглтону воссоздавать себя, если, скажем, вы используете ленивый init. Примерно так:

    public static Singletong GetInstance() {
      if (instance == null) {
        instance = new Singleton(); //here we re-evalute cache for example
       }
    return instance
    }
    public static void Reset() {
        instance = null;
    } 
    
1 голос
/ 28 мая 2010

Я согласен с ответом Кевина, но хотел бы кое-что добавить к этому. Я немного озадачен вашим заявлением:

Когда приложение закрывает это база данных должна быть удалена.

Вы действительно хотите удалить? Как в разрушенном? Вы говорите о реальной (SQL) базе данных?

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

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

То, что я пытаюсь сказать, это то, что, когда вы видите эту базу данных как ресурс приложения, вам нужно будет выполнить инициализацию и очистку не для объекта, а для приложения. В приложении ASP.NET это будет Application_Start и Application_End (global.asax). В приложении Windows Forms это будет Program.Main.

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

...