Вчера поздно вечером на работе мы пытались понять, почему что-то не работает. Проверка проверки не удалась, хотя этого не должно было быть.
В итоге мы добавили к этому коду оператор печати (дизассемблированный из Reflector, чтобы проверить, действительно ли код соответствует тому, что мы написали):
public static string Redacted(string name, DateTime lastModified)
{
long ticks = lastModified.Ticks;
if ((ticks != (ticks - (ticks % 10000L))) &&
(lastModified != DateTime.MaxValue))
{
Log.Debug(string.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'",
lastModified.ToString("dd/MM/yyyy hh:mm:ss.fff"),
ticks, ticks - (ticks % 10000L)));
Напечатано (переформатировано):
Last Modified Date = '22/03/2011 12:16:22.000'.
Ticks = '634363497820000000'.
TicksCalc = '634363497820000000'
Но условие состоит в том, что "ticks
" (что равно Ticks, напечатанному выше) не равно "(ticks - (ticks % 10000))
" (что равно TicksCalc)! 634363497820000000 != 634363497820000000?!
Чтобы определить, что здесь происходит, мы добавили еще два утверждения:
long ticks = lastModified.Ticks;
/* Added following two lines: */
long num2 = ticks - (ticks % 10000L);
Log.Debug((ticks == num2).ToString());
/* */
if ((ticks != (ticks - (ticks % 10000L))) &&
(lastModified != DateTime.MaxValue))
{
Log.Debug(string.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'",
lastModified.ToString("dd/MM/yyyy hh:mm:ss.fff"),
ticks, ticks - (ticks % 10000L)));
Как и должно было быть, этот напечатал true
(при тестировании с тем же значением) и не написал вторую строку.
Чувствуя себя немного потерянным, мы снова удалили две строки, перекомпилировали и перезапустили. Исходное поведение повторилось.
Сегодня утром я записал видео.
Видео в первую очередь показывает достижение точки останова в методе с использованием «сломанного» кода, а затем перестроение и повторный запуск с использованием «работающего» кода. Обратите внимание, что хотя отладчик показывает, что условие if
оценивается как false
, тело все равно вводится.
Я видел, как подобные вещи происходили раньше при наблюдении отладчиком из-за того, что отладчик принудительно оценивал некоторые вещи, но это происходит независимо от того, используется отладчик или нет.
Кроме того, это происходит только в режиме Release (т. е. с включенной JIT-оптимизацией).
Вот дизассемблированные методы для обеих версий: работает, не работает. Я не умею читать ассемблер, поэтому публикую их здесь в надежде на разъяснение.
Я надеюсь, что ответ не является чем-то очевидным, что я полностью упустил из виду...!
Редактировать: Вот IL. Я не думаю, что с этим что-то не так, потому что он декомпилируется до правильного C#:
Обновление:
Подтверждено Microsoft как ошибка, исправлено в следующей версии.
(ticks != ticks - (ticks % 10000L))
не эквивалентно(ticks % 10000L != 0)
? - person Phil Gan   schedule 26.05.2011assembly
? Я связал код сборки x86, содержащийся в этом вопросе... - person porges   schedule 27.05.2011