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

С#, странная оптимизация

Я пытаюсь прочитать мой скомпилированный код на С#.

это мой код:

using(OleDbCommand insertCommand = new OleDbCommand("...", connection))
{
   // do super stuff
}

Но!

Мы все знаем, что использование переводится на это:

{
    OleDbCommand insertCommand = new OleDbCommand("...", connection)
    try
    {
        //do super stuff
    }
    finally
    {
        if(insertCommand != null)
            ((IDisposable)insertCommand).Dispose();
    }
}

(поскольку OleDbCommand является ссылочным типом).

Но когда я декомпилирую свою сборку (скомпилированный с .NET 2.0), я получаю это в Resharper:

try
{
    insertCommand = new OleDbCommand("", connection);
Label_0017:
    try
    {
       //do super stuff
    }
    finally
    {
    Label_0111:
        if ((insertCommand == null) != null)
        {
            goto Label_0122;
        }
        insertCommand.Dispose();
    Label_0122:;
    }

Я говорю об этой строке: if ((insertCommand == null) != null).

Скажем, insertCommand IS null. Тогда первая часть возвращает true. (true != null) возвращает true. Итак, тогда распоряжение по-прежнему пропущено? Странно, очень странно.

Если я вставляю это в Visual Studio, Resharper уже предупреждает меня: выражение всегда верно...

Спасибо!

-Kristof

4b9b3361

Ответ 1

У декомпилятора есть ошибка. Эта строка

if ((insertCommand == null) != null) 

должен быть декомпилирован для

if ((insertCommand == null) != false)

который, хотя и без лишних слов, является, по крайней мере, правильным кодом.

Декомпилятор, вероятно, делает эту неоправданную подробную версию, потому что компилятор С# часто выбирает испускать

if (x)
   Y();
Z();

как будто вы написали

if (!x)
    goto L;
Y();
L: Z();

Поскольку код, сгенерированный для обеих программ, одинаковый, декомпилятор не всегда знает, какой из них является более разумным кодом для отображения.

Причина неожиданного "!= false" заключается в том, что, когда мы генерируем IL, который проверяет, является ли что-то истинным, самым быстрым и самым компактным кодом, который мы можем сгенерировать, является проверка того, является ли он неверным. False представляется как ноль в IL, и существует дешевая инструкция для "это вещь нуль?"

Ответ 2

когда вы декомпилируете код, вам не гарантированно вернуть исходный код. Когда .net-код компилируется в IL, он оптимизирован. Иногда вы увидите сумасшедшие, когда приложение переводит IL обратно в С#. Это не значит, что код не работает, это то, как приложение (resararper в этом случае) перевело IL.

Если вы беспокоитесь об этом, я бы посмотрел прямо на IL, чтобы посмотреть, что он был скомпилирован.

Боковое примечание: декомпилированный IL на С# или VB.net не гарантируется скомпилировать.:)

Еще один продукт, который нужно попробовать: Reflector