我最近在TryRoslyn上玩C#编译器,我遇到了一个奇怪的问题,即不等式检查被转换为大于一个。这是重现代码:
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;
}
}
这是重现的链接。罗斯林为什么要这样做;这是一个错误吗?
在玩了一段时间的代码后,我做了一些观察:
这仅发生在条件中的最后一个布尔表达式上。例如,如果添加另一个
||
语句,则只会在最后一次调用Foo()
时发生。它也只发生在 0 上,特别是;如果你用它代替
1
或其他数字,它就不会发生。
反编译代码是错误的;这是反编译器中的错误,而不是编译器中的错误。生成的 IL 是正确的。请仔细阅读 IL。你明白为什么大于比较是正确的而反编译是错误的吗?
至于为什么这个代码只发生在操作员的右侧,我不记得了。 如果你想在代码生成器中探索,它在这里:
https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs
你想要方法EmitIsNonNullOrZero
.