Является ли злоупотребление IDisposable полезным для "использования" заявлений, считающихся вредоносными?
Целью интерфейса IDisposable
является упорядоченное упорядочение неуправляемых ресурсов. Он идет рука об руку с ключевым словом using
, который определяет область, по истечении которой данный ресурс удаляется.
Потому что этот мехнизм настолько опрятен, что я неоднократно испытывал желание внедрить классы IDisposable
, чтобы иметь возможность злоупотреблять этим механизмом способами, для которых он не предназначен. Например, можно было бы реализовать классы для обработки вложенных контекстов, таких как:
class Context : IDisposable
{
// Put a new context onto the stack
public static void PushContext() { ... }
// Remove the topmost context from the stack
private static void PopContext() { ... }
// Retrieve the topmost context
public static Context CurrentContext { get { ... } }
// Disposing of a context pops it from the stack
public void Dispose()
{
PopContext();
}
}
Использование кода вызова может выглядеть так:
using (Context.PushContext())
{
DoContextualStuff(Context.CurrentContext);
} // <-- the context is popped upon leaving the block
(Обратите внимание, что это всего лишь пример, а не тема этого вопроса.)
Тот факт, что Dispose()
вызывается из области действия оператора using
, также может быть использован для реализации всех видов вещей, которые зависят от области видимости, например. таймеры. Это также можно было бы использовать с помощью конструкции try ... finally
, но в этом случае программисту пришлось бы вручную вызвать какой-либо метод (например, Context.Pop
), который конструктор using
мог бы сделать для thon.
Это использование IDisposable
не совпадает с его назначением как указано в документации, однако искушение сохраняется.
Есть ли конкретные причины, чтобы проиллюстрировать, что это плохая идея и развеять мои фантазии навсегда, например, осложнения с сборкой мусора, обработку исключений и т.д. Или я должен идти дальше и побаловать себя, злоупотребляя этой концепцией языка таким образом?
Ответы
Ответ 1
Итак, в представлениях MVC MVC, мы видим следующую конструкцию:
using(Html.BeginForm())
{
//some form elements
}
Оскорбление? Microsoft говорит "нет" (косвенно).
Если у вас есть конструкция, для которой требуется, что-то произойдет, как только вы закончите с ней, IDisposable
может часто работать довольно хорошо. Я делал это несколько раз.
Ответ 2
"Это злоупотребление интерфейсом IDisposable
, чтобы использовать его таким образом"? Возможно.
Использует ли using
как чисто "область видимости" для более очевидного намерения и лучшей читаемости кода? Конечно.
Последний козыряет первое для меня, поэтому я говорю, что использую его.
Ответ 3
Вы, конечно, не были бы первым, кто "злоупотреблял" IDisposable таким образом. Вероятно, мое любимое использование в таймерах, так как клиент StatsD.NET демонстрирует:
using StatsdClient;
...
using (statsd.LogTiming( "site.db.fetchReport" ))
{
// do some work
}
// At this point your latency has been sent to the server
На самом деле, я уверен, что сами Microsoft используют его в некоторых библиотеках. Мое эмпирическое правило будет - если оно улучшит читаемость, пойдите для него.