Любопытный С# с использованием расширения оператора
Я запустил 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 будет выполняться только в том случае, если выполняется блок try, и блок try будет выполнен только в том случае, если Simple-конструктор успешно завершит работу (I.e. не генерирует исключение), и в этом случае simp будет не нулевым. (Если есть некоторые опасения, что некоторые промежуточные шаги могут возникнуть между Простым конструктором и началом блока 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
}
Ответы
Ответ 1
Нет, блок finally будет выполняться ВСЕГДА. Возможно, вы не получаете объект от нового, а из какой-либо другой функции, возвращающей ваш объект, и он может вернуть NULL. using() - ваш друг!
dss539 был достаточно любезен, чтобы предложить включить его примечание:
using(Simple simp = null)
- еще одна причина того, что расширение должно сначала проверить значение null.
Ответ 2
using(Simple simp = null)
еще еще одна причина, что расширение должно сначала проверять значение null.
Ответ 3
MSDN в инструкции using.
Я считаю странным, что он не распространяется на:
Simple simp = new Simple();
Simple __compilergeneratedtmpname = simp;
try
{
Console.WriteLine("here");
}
finally
{
if(__compilergeneratedtmpname != null)
{
__compilergeneratedtmpname.Dispose();
}
}
Ответ 4
Похоже, что ваш комментарий:
"Если есть какой-то страх, что некоторые промежуточные шаги могут возникнуть между Простым конструктором и началом блока try, то это действительно будет проблемой, потому что тогда может быть создано исключение, которое предотвратило бы выполнение блока finally в все".
возможно мертв. См:
Атоматичность и асинхронные сбои исключений
Я также хочу отметить проблемы с WCF и использовать:
Избежать проблем с использованием оператора Statement и служебных прокси WCF, в котором приведены ссылки:
Избежать проблем с использованием заявления