С#, странная оптимизация
Я пытаюсь прочитать мой скомпилированный код на С#.
это мой код:
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
Ответы
Ответ 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