Я делаю рефакторинг своих библиотек, чтобы Span<T>
по возможности избегать выделения кучи, но поскольку я нацеливаюсь и на более старые фреймворки, я также реализую некоторые общие резервные решения. Но теперь я обнаружил странную проблему и не совсем уверен, нашел ли я ошибку в .NET Core 3 или я делаю что-то нелегальное.
Проблема:
// This returns 1 as expected but cannot be used in older frameworks:
private static uint ReinterpretNew()
{
Span<byte> bytes = stackalloc byte[4];
bytes[0] = 1; // FillBytes(bytes);
// returning bytes as uint:
return Unsafe.As<byte, uint>(ref bytes.GetPinnableReference());
}
// This returns garbage in .NET Core 3.0 with release build:
private static unsafe uint ReinterpretOld()
{
byte* bytes = stackalloc byte[4];
bytes[0] = 1; // FillBytes(bytes);
// returning bytes as uint:
return *(uint*)bytes;
}
Интересно, что он ReinterpretOld
хорошо работает в .NET Framework и .NET Core 2.0 (так что я мог бы быть доволен этим в конце концов), тем не менее, это немного беспокоит меня.
Btw. ReinterpretOld
может быть исправлено также в .NET Core 3.0 с помощью небольшой модификации:
//return *(uint*)bytes;
uint* asUint = (uint*)bytes;
return *asUint;
Мой вопрос:
Это ошибка или она ReinterpretOld
работает в старых фреймворках только случайно, и я должен применить исправление также для них?
Примечания:
- Отладочная сборка работает также в .NET Core 3.0
- Я пытался применить
[MethodImpl(MethodImplOptions.NoInlining)]
к ,ReinterpretOld
но это не имело никакого эффекта.
stackalloc
(то есть не
return Unsafe.As<byte, uint>(ref bytes[0]);
илиreturn MemoryMarshal.Cast<byte, uint>(bytes)[0];
- нет необходимости использоватьGetPinnableReference()
; хотя заглядываем в другое