Утилизация одиночного экземпляра (C #) - PullRequest
2 голосов
/ 03 июня 2011

Если в Singleton реализована функция IDisposable, каков правильный способ удаления и повторного создания экземпляра? Один из способов - сохранить флаг _disposed и проверить его в свойстве Instance, но я не уверен, что это правильный способ сделать это. Простой пример:


public sealed class Singleton: IDisposable
{
   private static Singleton _instance;
   private object _lock;
   private UnmanagedResource _unmanaged;
   private bool _disposed;

   private Singleton()
   {
      _unmanaged = new UnmanagedResource();
      _disposed  = false;
      _lock      = new object();
   }

   public UnmanagedResource Unmanaged { get { return _unmanaged; } }

   public static Singleton Instance
   {
      get
      {
         if (_instance == null || _disposed)
         {
            lock (_lock)
            {
               if (_instance == null || _disposed)
               {
                  _instance = new Singleton();
               }
            }
         }
         return _instance;
      }
   }

   public void Dispose()
   {
      _disposed = true;
      try
      {
         _unmanaged.Dispose();
      }
      finally
      {
         GC.SuppressFinalize(this);
      }
   }
}

Так что код, которому нравится это, возможно (хотя, да, я согласен, это отчасти побеждает цель наличия Singleton):


Singleton.Instance.Dispose();
Singleton.Instance.Unmanaged.UseResource();   // Unmanaged shouldn't be null.

ПРИМЕЧАНИЕ: Нет необходимости переоценивать несовместимость между Singleton и IDisposable, я так понимаю. Мне нужен метод Dispose для освобождения неуправляемых ресурсов при выгрузке ApppDomain. Если у вас есть проблема с тем, что этот класс называется Singleton, я могу переименовать его в LoadBalancer. Вопрос останется прежним. Этот LoadBalancer должен быть одноразовым, потому что его экземпляр не принадлежит никому, но должен быть правильно утилизирован.

Ответы [ 4 ]

6 голосов
/ 03 июня 2011

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

если вы ДЕЙСТВИТЕЛЬНО думаете, что должны это сделать, я бы предложил использовать 2 объекта ...

один одноэлементный объект, который действует как прокси и является реальным одноэлементным (конец времени жизни == конец процесса)

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

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

6 голосов
/ 03 июня 2011

Одиночные и одноразовые объекты в значительной степени несовместимы.

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

Синглтоны, как правило, живы в течение всего жизненного цикла процесса / AppDomain.Если вы захотите Dispose их, то вам, вероятно, потребуется немного реорганизовать решение.

Если проблема заключается в освобождении ресурсов во время выгрузки AppDomain, тогда возьмите на себя ответственность за освобождение ресурсас тем же объектом, ответственным за управление временем жизни AppDomain.Затем вставьте этот ресурс в Singleton без реализации IDisposable.Это правильно выделит проблемы сценария.

2 голосов
/ 03 июня 2011

Я не вижу, как это будет работать.Рассмотрим этот гипотетический вариант использования:

using (Singleton instance = Singleton.Instance)
{
  // Do stuff with the instance.
}

Как вы собираетесь защититься от нескольких потоков, выполняющих этот код одновременно?Один поток может вызвать Dispose, в то время как другой все еще пытается использовать тот же экземпляр.Попытка использовать API с переработкой семантики в концепцию синглтона - это все равно, что попытаться вписать квадратный колышек в круглое удержание.

Кстати, есть и тангенциальные проблемы, которые стоит упомянуть.Свойство Instance не является потокобезопасным.По крайней мере, вам нужно пометить _instance как volatile.И это только в том случае, если вы использовали каноническую реализацию шаблона.Вы никогда не сможете сделать шаблон безопасным, поскольку вы также используете флаг _disposed в качестве дополнительного критерия при проверке.Лично я бы просто отказался от двойной проверки схемы блокировки.

0 голосов
/ 03 июня 2011

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

Это может быть проблема дизайна, о которой я не знаю. Возможно, «правильный путь» в этом случае - переоценить то, что вам нужно, чтобы ваш код делал, и какой шаблон вас туда привел.

...