Почему кастинг с байта на sbyte дает неправильное значение для оптимизированного кода?

Проблема может быть воспроизведена с помощью следующего примера кода, с установленным NUnit 3.

[TestFixture]
public class SByteFixture
{
    [Test]
    public void Test()
    {
        var data = new byte[] { 0xFF };

        sbyte x = -128;
        data[0] = (byte) x;
        byte b1 = data[0];
        var b2 = (sbyte) b1;
        Assert.AreEqual(b1.ToString(), "128");
        Assert.AreEqual(b2.ToString(), "-128");
    }
}
  1. Проект должен быть библиотекой классов, потому что в консольном приложении он не воспроизводится.
  2. Должна быть включена оптимизация, т.е. Следующая настройка в файле csproj:

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <Optimize>true</Optimize>
    </PropertyGroup>
    

Тест проходит, когда Optimize является ложным, но он терпит неудачу, когда Optimize истинно (b2.ToString() дает "128").

Это можно увидеть с помощью ReSharper для запуска теста или NUnitConsole, не воспроизводимого с помощью VS Test Explorer.

Как это можно объяснить?

Ответы

Ответ 1

Как предположил @HansPassant, я сообщил об этой проблеме в GitHub, и, похоже, это подтвержденная ошибка.

Здесь цитата по этому вопросу из mikedn

Тот факт, что вы можете воспроизвести в библиотеке классов, а не в консольном приложении, может означать, что вы используете.NET Framework, а не.NET Core. В консольных приложениях.NET Framework по умолчанию 32 бит, поэтому они используют устаревший JIT32, а не RyuJIT. 64-разрядные приложения.NET Framework используют RyuJIT, но обычно это более старая версия, чем версия.NET Core.

Я могу воспроизвести эту проблему с использованием 64-битной.NET Framework 4.7.2, но не текущей основной версии.NET Core. Он может воспроизводиться с использованием.NET Core 2.1, поэтому, вероятно, это уже было исправлено в master.