C# 即使条件的计算结果为false,If语句似乎也在计算

C# 即使条件的计算结果为false,If语句似乎也在计算,c#,.net,assembly,x86,.net-assembly,C#,.net,Assembly,X86,.net Assembly,昨晚工作到很晚,我们试图弄清楚为什么有些东西出了问题。验证检查本不应该失败,但却失败了 最后,我们在代码中添加了一个print语句(从Reflector中进行反汇编,以检查代码是否与我们编写的代码相同): 它打印(重新格式化): 但条件是“滴答声”(等于上面打印的滴答声)不等于“(滴答声-(滴答声%10000))(等于滴答声)!634363497820000000 != 634363497820000000?! 为了确定这里发生了什么,我们添加了另外两条语句: long ticks = last

昨晚工作到很晚,我们试图弄清楚为什么有些东西出了问题。验证检查本不应该失败,但却失败了

最后,我们在代码中添加了一个print语句(从Reflector中进行反汇编,以检查代码是否与我们编写的代码相同):

它打印(重新格式化):

但条件是“
滴答声”
(等于上面打印的滴答声)不等于“
(滴答声-(滴答声%10000))
(等于滴答声)!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
,主体仍会被输入

我以前在调试器观察时见过类似的情况,这是因为调试器强制对某些内容进行求值,但无论是否使用调试器,都会发生这种情况

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

以下是两个版本的反汇编方法:。我真的看不懂汇编,所以我把它们贴在这里,希望能解释清楚

我希望答案不是我完全忽略的显而易见的东西

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

更新

.

检查此线程

归根结底,你不能一直信任调试器


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

这太疯狂了。你有没有尝试过,没有好的理由,重新排序if语句

if (lastModified != DateTime.MaxValue && ticks != (ticks - (ticks % 10000L))
另外,如果这不起作用(考虑到它本来不应该是一个问题,它应该不起作用),您能以有问题的形式显示代码的实际IL吗

还有一件事,
ticks
检查不能简化为:

(ticks % 10000L) != 0

这看起来确实像一个-啊哈-吉特虫。你能不能在“if”语句上设置一个断点,并在它出现后给我们看一个反汇编视图的屏幕截图?

我刚才也有类似的例子。 在我的例子中,这与我比较两个整数值有关,其中一个值实际上是对一个装箱整数的引用,另一个是一个真正的原语值

问题是,如果打印出装箱整数和原语的值,它们看起来是一样的,但是比较它们是另一回事。您将得到一个引用比较,而不是值比较

答案很简单:

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

我尝试了一些简化代码:

最有趣的变化是:

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(); 
     } 
 }
如果我将
variableZero
替换为
constantZero
,它会工作


所以我很确定这不是抖动就是编译错误

我已经提交了一份关于MS Connect的错误报告:


更新:只有在未附加调试器的情况下才会发生奇怪的行为。i、 e.启用Jit优化时。所以我很确定这是一个抖动错误


对于没有linq pad的用户,现在有一个简单的C#控制台项目:

很棒的视频!很久没有看到这样的行为了。我曾经有过同样的问题(但在Java中)。添加一个“System.out.println();”也为我解决了这个问题。这真的很奇怪…@Porges我们能得到MSIL(.NET程序集,而不是x86程序集:)吗?您可以使用.NET反射器获取所需的特定方法。@pickypg:我已经添加了它。我不认为它有什么问题,因为它可以反编译成正确的C代码(不过我还没有亲自检查过)。@ohmantics:你能解释一下为什么要删除
程序集
标记吗?我已经链接了这个问题中包含的x86汇编代码……我已经向MS connect提交了一份错误报告:无论我是否连接了调试器,这种行为都会发生(第一个输出来自未连接调试器的运行)。我只是连接到这里,以便能够在那里中断并确保。事实上,我直到今天早上才连接调试器,因此第一次输出、“修复”以及删除“修复”时的复制都没有调试器的干扰。因此,很抱歉。不幸的是,我现在没有时间分析它,但如果没有其他人,我明天会再看一看。哇,谢谢!我认为不可能在我们图书馆的背景下复制它:)RE:Update-我想我在原始帖子中提到过这一点,但我似乎已经把它删掉了。我要补充一点,他们(最终)已经回复了这个bug,并声明它将在下一个框架版本中修复。我再次检查,它似乎不在最近的KB2468871/KB2533523版本中,所以希望它将是下一个版本。将此标记为答案。
long ticks = lastModified.Ticks;
long num2 = ticks - (ticks % 10000L);
if ((ticks != num2) && (lastModified != DateTime.MaxValue))
{ do your thing here! }
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(); 
     } 
 }