2010-06-11 2 views
8

В моих методах Dispose (например, ниже) каждый раз, когда я хочу вызвать someObj.Dispose(), у меня также есть чек для someObj! = Null.Устранение элементов, реализующих IDisposable

Это из-за плохой конструкции с моей стороны? Является ли их более чистым способом убедиться в том, что Dispose всех членов (реализующих IDisposable), используемых в объекте, вызывается без риска исключения NullReference?

protected void Dispose(bool disposing) 
     { 
      if (disposing) 
      { 
       if (_splitTradePopupManager != null) 
       { 
        _splitTradePopupManager.Dispose(); 
       } 
      } 
     } 

Спасибо за ваш интерес.

ответ

4

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

Тем не менее, ничто не мешает вам оборачивать ваш null чек и Dispose вызов в удобном методе:

private void DisposeMember(IDisposable member) 
{ 
    if (member != null) 
     member.Dispose(); 
} 

Тогда ваш метод Dispose может выглядеть немного чище:

protected void Dispose(bool disposing) 
{ 
    if (disposing) 
    { 
     DisposeMember(_splitTradePopupManager); 
     DisposeMember(_disposableMember2); 
     DisposeMember(_disposableMember3); 
    } 
} 

В качестве дополнительного бонус, это также разрешает потенциальное состояние гонки в вашем исходном коде. Если работает в многопоточном контексте, то шаблон if (_field != null) _field.Dispose() может привести к NullReferenceException, когда _field установлено в null между проверкой и удалением (редко, но возможно). Передача _field в качестве аргумента для метода, такого как DisposeMember, копирует ссылку на локальную переменную в методе, исключая эту возможность, маловероятную, как есть.

+1

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

+0

@ccomet: +1, у меня такое же мышление (слишком осторожное) в глубине души, когда вы вызываете Dispose() на объект. –

0

Только вы знаете ответ на этот вопрос!

Не видя своего класса, сложно кому-либо еще сказать, возможно ли, что эти члены когда-либо будут иметь нулевое значение, когда вызывается Dispose.

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

0

Единственный другой вариант, о котором я мог думать, это создать вспомогательный метод DisposeParameter, который имеет объект как его параметр и только проверяет, имеет ли он значение null и в противном случае утилизирует его. Таким образом вам понадобится только одна строка кода, чтобы избавиться от нее, но я не уверен, что это сделает ее более читаемой.

-1

Попробуйте это.

protected void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      //for all members.. 
      if (null != member && member is IDisposible) 
      { 
       member.Dispose(); 
      } 
     } 
    } 
+0

Я не уверен, что понимаю, что вы предлагаете здесь. –

+0

может кто-то оправдать отрицательный голос ?? –

+4

Это был не я, но проверка того, является ли элемент 'IDisposable' немного глупым, потому что вызов' member.Dispose() 'не будет компилироваться, когда' member' не был одноразовым типом. – Steven

9

Мне нравится решение @Dan Тао, но это намного лучше, так как метод расширения, имо:

public static void SafeDispose(this IDisposable obj) 
{ 
    if (obj != null) 
     obj.Dispose(); 
} 

Теперь вы можете просто позвонить по любому member.SafeDispose()IDisposable в вашей программе без беспокойства. :)

+0

Это не приведет к исключению нулевой ссылки при попытке вызвать метод расширения? Edit-- Я написал приложение для быстрого тестирования, и он отлично работает! –

+0

Нет, не будет. Я использовал аналогичный подход в проекте (DisposeIfNotNull()). –

+2

Нет! Так как оператор-точка является просто синтаксическим сахаром для статического метода, он работает отлично. :) – tzaman