Estou refatorando minhas bibliotecas Span<T>
para evitar alocações de heap, se possível, mas como eu viso também estruturas mais antigas, também estou implementando algumas soluções gerais de fallback. Mas agora encontrei um problema estranho e não tenho certeza se encontrei um bug no .NET Core 3 ou estou fazendo algo ilegal.
O problema:
// 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;
}
Curiosamente, ReinterpretOld
funciona bem no .NET Framework e no .NET Core 2.0 (para que eu possa ficar feliz com isso, afinal), ainda assim, isso me incomoda um pouco.
Btw. ReinterpretOld
também pode ser corrigido no .NET Core 3.0 com uma pequena modificação:
//return *(uint*)bytes;
uint* asUint = (uint*)bytes;
return *asUint;
Minha pergunta:
Isso é um bug ou ReinterpretOld
funciona em estruturas mais antigas apenas por acidente e devo aplicar a correção também a elas?
Observações:
- A compilação de depuração também funciona no .NET Core 3.0
- Eu tentei aplicar
[MethodImpl(MethodImplOptions.NoInlining)]
paraReinterpretOld
, mas não teve nenhum efeito.
stackalloc
(ou seja, não limpe o espaço alocado)
return Unsafe.As<byte, uint>(ref bytes[0]);
oureturn MemoryMarshal.Cast<byte, uint>(bytes)[0];
- não há necessidade de usarGetPinnableReference()
; olhando para a outra parte, porém