如果语句似乎正在评估,即使条件评估为false

昨晚工作到很晚,我们试图弄清楚为什么会出现问题。 如果不应该进行validation检查失败。

我们最终在这段代码中添加了一个print语句(从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 (当测试时使用相同的值),并且没有写第二行。

感觉有点迷失,我们再次删除了两行,重新编译,并重新。 原来的行为重演了。

今天早上, 我录制了一段video 。

首先,video显示使用“损坏”代码在方法中命中断点,然后使用“工作”代码重建和重新运行。 请注意,即使调试器显示if条件的计算结果为false ,仍然会输入正文。

我已经看到这样的事情发生在调试器观察之前,因为调试器强制要求评估一些事情,但无论是否使用调试器都会发生这种情况。

此外,这仅在发布模式下发生(即启用了JIT优化)。

以下是两个版本的反汇编方法: 工作 , 不工作 。 我不能真正阅读汇编,所以我将它们发布在这里是为了澄清。

我希望答案不是我完全忽略的明显的答案……!

编辑:这是IL。 我认为它没有任何问题,因为它反编译为正确的C#:

  • 不工作
  • 工作

更新

被Microsoft确认为bug,将在下一个版本中修复 。

我用简化的代码进行了一些实验: http : //nopaste.info/2c99a0e028_nl.html

最有趣的变化是:

 static readonly long variableZero=0; const long constZero=0; public static void Broken2( long ticks2) { long ticks = ticks2+variableZero; if (ticks != (ticks - (ticks % 10000L))) { string.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'", "n/A", ticks, ticks - (ticks % 10000L)).Dump(); } } 

如果我用constantZero替换variableZero它可以工作。


所以我很确定它是一个抖动或编译器错误。

我已经在MS Connect上提交了一个bug报告: https : //connect.microsoft.com/VisualStudio/feedback/details/671105/jitter-or-c-compiler-bug#details


更新 :仅在未附加调试器时才会出现奇怪的行为。 即启用Jit优化时。 所以我很确定这是一个抖动错误。

对于没有linq-pad的人来说,现在有一个简单的C#控制台项目: http : //nopaste.info/00a0e37328_nl.html

看看这个post。

如果在Visual Studio 2008中声明怪异

归结到这一点,你无法一直信任调试器。

要“修复”if语句,请向其添加一个空的else {}语句。 调试器将按预期工作。

这确实看起来像是 – 哼哼 – jitterbug。 你可以在“if”语句中设置一个断点,并在它击中之后向我们展示反汇编视图的截图吗?

我刚才有类似的东西。 在我的情况下,它与我正在比较2个整数值的事实有关,其中一个值实际上是对盒装整数的引用而另一个值是真正的原始值。

问题是如果你打印出盒装整数和基元的值,它们看起来是一样的,但比较它们是另一回事。 您将获得参考比较而不是值比较。

答案很简单:

 long ticks = lastModified.Ticks; long num2 = ticks - (ticks % 10000L); if ((ticks != num2) && (lastModified != DateTime.MaxValue)) { do your thing here! } 

太疯狂了。 您是否尝试过重新排序if语句?

 if (lastModified != DateTime.MaxValue && ticks != (ticks - (ticks % 10000L)) 

此外,如果这不起作用(因为它不应该,首先考虑它不应该是一个问题),你能否以有问题的forms显示代码的实际IL?

另外一件事,不能将ticks检查简化为:

 (ticks % 10000L) != 0