Любопытный C # с использованием расширения оператора - PullRequest
26 голосов
/ 04 июня 2009

Я запустил ildasm, чтобы найти это:

    using(Simple simp = new Simple())
    {
        Console.WriteLine("here");
    }

генерирует код IL, эквивалентный этому:

    Simple simp = new Simple();
    try
    {
        Console.WriteLine("here");
    }
    finally
    {
        if(simp != null)
        {
            simp.Dispose();
        }
    }

и вопрос в том, почему, черт возьми, он проверяет ноль в наконец? Блок finally будет выполняться только в том случае, если выполняется блок try, а блок try будет выполняться только в том случае, если простой конструктор завершается успешно (т. Е. Не выдает исключение), и в этом случае simp будет отличным от NULL. (Если есть некоторый страх, что некоторые промежуточные шаги могут возникнуть между конструктором Simple и началом блока try, тогда это действительно будет проблемой, потому что тогда может возникнуть исключение, которое вообще не позволит выполнить блок finally.) Итак, какого черта?

Откладывая (пожалуйста) аргумент о том, лучше ли использование оператора, чем 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
    }

Ответы [ 4 ]

22 голосов
/ 04 июня 2009

Нет, блок finally ВСЕГДА будет выполняться. Возможно, вы не получаете объект из новой, но из какой-то другой функции, которая возвращает ваш объект - и он может возвращать NULL. используя () ваш друг!

dss539 был достаточно любезен, чтобы предложить включить его примечание:

using(Simple simp = null) 

- это еще одна причина, по которой расширение должно сначала проверять наличие нуля.

11 голосов
/ 04 июня 2009

using(Simple simp = null) - это еще другая причина, по которой расширение должно сначала проверять наличие нуля.

4 голосов
/ 04 июня 2009

MSDN в операторе использования.

Что мне кажется странным, так это то, что оно не расширяется до:

Simple simp = new Simple();
Simple __compilergeneratedtmpname = simp;
try
{
    Console.WriteLine("here");
}
finally
{
    if(__compilergeneratedtmpname != null)
    {
        __compilergeneratedtmpname.Dispose();
    }
}
1 голос
/ 23 марта 2010

Похоже, что ваш комментарий:

"Если есть некоторый страх, что между конструктором Simple и началом блока try могут возникнуть какие-то промежуточные шаги, тогда это действительно будет проблемой, потому что тогда может возникнуть исключение, которое не позволит выполнить блок finally при все. "

возможно мертв. См:

Атомные и асинхронные исключения исключений

Я также хочу отметить проблему (и) с WCF и использовать:

Предотвращение проблем с использованием оператора Statement и прокси служб WCF , который ссылается на:

Как избежать проблем с помощью оператора Using

...