Подтвердить что ты не робот

Любопытный С# с использованием расширения оператора

Я запустил 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
    }
4b9b3361

Ответ 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, в котором приведены ссылки:

Избежать проблем с использованием заявления