Sto eseguendo il refactoring delle mie librerie da utilizzare Span<T>
per evitare allocazioni di heap, se possibile, ma poiché mi rivolgo anche a framework più vecchi, sto implementando anche alcune soluzioni generali di fallback. Ma ora ho riscontrato uno strano problema e non sono sicuro se ho trovato un bug in .NET Core 3 o sto facendo qualcosa di illegale.
Il 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;
}
È interessante notare che ReinterpretOld
funziona bene in .NET Framework e .NET Core 2.0 (quindi potrei esserne contento dopo tutto), tuttavia mi disturba un po '.
Btw. ReinterpretOld
può essere risolto anche in .NET Core 3.0 con una piccola modifica:
//return *(uint*)bytes;
uint* asUint = (uint*)bytes;
return *asUint;
La mia domanda:
Si tratta di un bug o ReinterpretOld
funziona nei framework più vecchi solo per caso e dovrei applicare la correzione anche per loro?
Osservazioni:
- La build di debug funziona anche in .NET Core 3.0
- Ho cercato di applicare
[MethodImpl(MethodImplOptions.NoInlining)]
aReinterpretOld
, ma non ha avuto alcun effetto.
stackalloc
(cioè non cancella lo spazio assegnato)
return Unsafe.As<byte, uint>(ref bytes[0]);
oppurereturn MemoryMarshal.Cast<byte, uint>(bytes)[0];
- non è necessario utilizzareGetPinnableReference()
; guardando dall'altra parte, però