为什么 Roslyn 在这里生成一个>比较而不是 != 一个?



我最近在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 .

最新更新