Je refactorise mes bibliothèques Span<T>
pour éviter les allocations de tas si possible, mais comme je cible également des cadres plus anciens, j'implémente également des solutions de secours générales. Mais maintenant, j'ai trouvé un problème étrange et je ne sais pas trop si j'ai trouvé un bogue dans .NET Core 3 ou si je fais quelque chose d'illégal.
Le problème:
// 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;
}
Il est intéressant de noter que cela ReinterpretOld
fonctionne bien dans .NET Framework et dans .NET Core 2.0 (donc je pourrais en être satisfait après tout), mais cela me dérange un peu.
Btw. ReinterpretOld
peut également être corrigé dans .NET Core 3.0 par une petite modification:
//return *(uint*)bytes;
uint* asUint = (uint*)bytes;
return *asUint;
Ma question:
Est-ce un bogue ou ne ReinterpretOld
fonctionne- t-il que par accident dans les anciens frameworks et dois-je également appliquer le correctif pour eux?
Remarques:
- La version de débogage fonctionne également dans .NET Core 3.0
- J'ai essayé d'appliquer
[MethodImpl(MethodImplOptions.NoInlining)]
àReinterpretOld
mais il n'a eu aucun effet.
stackalloc
(c'est-à-dire qu'il n'efface pas l'espace alloué)
return Unsafe.As<byte, uint>(ref bytes[0]);
oureturn MemoryMarshal.Cast<byte, uint>(bytes)[0];
- pas besoin d'utiliserGetPinnableReference()
; en regardant l'autre, cependant