Я запустил ildasm и обнаружил, что это:
using(Simple simp = new Simple())
{
Console.WriteLine("here");
}
генерирует код IL, который эквивалентен этому:
Simple simp = new Simple();
try
{
Console.WriteLine("here");
}
finally
{
if(simp != null)
{
simp.Dispose();
}
}
и вопрос в том, какого черта он проверяет null в finally? Блок finally будет выполняться только в том случае, если выполняется блок try, а блок try будет выполняться только в том случае, если конструктор Simple завершается успешно (т. е. не генерирует исключение), и в этом случае simp будет ненулевым. (Если есть некоторый страх, что между конструктором Simple и началом блока try могут возникнуть какие-то промежуточные шаги, то это действительно будет проблемой, потому что тогда может быть выброшено исключение, которое вообще предотвратит выполнение блока finally.) Так почему, черт возьми?
Отложив в сторону (пожалуйста) аргумент о том, что оператор using лучше, чем try-finally, я пишу свои блоки try-finally следующим образом:
Simple simp = new Simple();
try
{
Console.WriteLine("here");
}
finally
{
simp.Dispose();
simp = null; // sanity-check in case I touch simp again
// because I don't rely on all classes
// necessarily throwing
// ObjectDisposedException
}