Ostatnio grałem z kompilatorem C# na TryRoslyn, a natknąłem się na dziwny problem, w którym kontrola nierówności została przekształcona w większą niż jedną. Oto kod repro:Dlaczego Roslyn generuje> porównanie zamiast a! = Tutaj?
using System;
public class C {
public void M() {
if (Foo() != 0 || Foo() != 0)
{
Console.WriteLine("Hi!");
}
}
private int Foo() => 0;
}
i tutaj jest kod, który zostanie wygenerowany przez dekompilator:
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 link do Repro. Dlaczego Roslyn to robi; czy to błąd?
Niektóre obserwacje zrobiłem po zabawy z kodem na chwilę:
Dzieje się tak tylko z ostatniego logicznej wypowiedzi w stanie. Na przykład, jeśli dodasz inne oświadczenie
||
, stanie się to tylko przy ostatnim połączeniu zFoo()
.To samo dzieje się tylko z 0, konkretnie; jeśli zastąpisz go
1
lub inną liczbą, to się nie stanie.
W porządku, wydaje mi się, że widzę problem; opkodem jest 'cgt.un', który wykonuje unsigned porównania, więc dekompilowany kod powinien naprawdę być' (uint) this.Foo()> (uint) 0' (co jest prawdziwe dla wszystkich niezerowych int). Dziękuję za wskazanie tego. –
@JamesKo: Dokładnie tak! –