我最近在TryRoslyn上玩C#编译器,我遇到了一个奇怪的问题,即不等式检查被转换为大于一的。这是repro代码:
using System;
public class C {
public void M() {
if (Foo() != 0 || Foo() != 0)
{
Console.WriteLine("Hi!");
}
}
private int Foo() => 0;
}
以下是反编译器生成的代码:
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyVersion("0.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[module: UnverifiableCode]
public class C
{
public void M()
{
bool flag = this.Foo() != 0 || this.Foo() > 0; // this should be an != check
if (flag)
{
Console.WriteLine("Hi!");
}
}
private int Foo()
{
return 0;
}
}
Here's指向repro的链接。为什么罗斯林会这样做;这是一个错误吗?
在玩了一段时间之后,我已经做了一些观察:
这只发生在条件中的最后一个布尔表达式。例如,如果您添加另一个||
语句,则只会在最后一次调用Foo()
时发生。
它也只发生在0,具体而言;如果您将其替换为1
或其他一些数字,则不会发生。
答案 0 :(得分:11)
反编译代码错误;这是反编译器中的错误,而不是编译器。生成的IL是正确的。 非常仔细阅读IL 。你明白为什么大于比较是正确的并且反编译是错误的吗?
至于为什么这个codegen只发生在操作员的右侧,我不记得了。如果你想在代码生成器中进行探索,那就在这里:
https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs
您需要方法EmitIsNonNullOrZero
。