Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V .NET 11 se nekontrolované převody z typů s plovoucí desetinnou čárkou na sbyte, byte, short, ushort a char nyní chovají saturačně na mezích cílového typu. Hodnoty, které jsou příliš malé nebo příliš velké, jsou nastaveny na minimální nebo maximální hodnotu cílového typu.
Tato změna navazuje na změnu v .NET 9 týkající se převodů z hodnot s plovoucí desetinnou čárkou na celá čísla, která standardizovala převody z float a double na int, uint, long a ulong. .NET 11 rozšiřuje saturaci i na 8bitové a 16bitové cílové typy.
Tato změna platí pro CoreCLR, včetně jeho interpreta a nativní AOT. Mono není součástí této změny.
Další informace najdete v tématu dotnet/runtime#128604.
Verze byla představena
.NET 11 Preview 7
Předchozí chování
Dříve platforma .NET nezaručovala výsledek neověřovaného převodu z čísla s plovoucí desetinnou čárkou na celočíselný typ, pokud hodnota přetekla cílový typ nebo byla NaN. Výsledky se můžou lišit mezi implementacemi modulu runtime, jako je CoreCLR a Mono, mezi architekturami, jako jsou x86, x64, Arm32, Arm64 a WebAssembly, a mezi hardwarovými instrukčními sadami v rámci architektury, jako jsou x87, SSE2, AVX a AVX-512.
Zásadní změna .NET 9 konkrétně zvýraznila x86 a x64, kde převody běžně vrací hodnoty sentinelu při přetečení. Arm64 již standardně používal saturační konverze. Tato změna standardizovala převody na širší celočíselné typy, namísto toho, aby stanovila staré sentinelové hodnoty jako závazné chování.
U malých integrálních typů byla v .NET 9 a .NET 10 běžnou posloupností převodů v CoreCLR saturační konverze na int, po níž následovalo zúžení na cílový typ odstraněním vyšších bitů. Tato sekvence vysvětluje chování, které zaznamenalo mnoho aplikací, ale nešlo o garantované chování při přímém přetypování z typu s plovoucí desetinnou čárkou na malý celočíselný typ.
Následující tabulka zobrazuje výsledky této dvoukrokové posloupnosti pro hodnotu modulu runtime float nebo doublex. Tyto vstupy se vejdou do int, takže příklady ukazují dopad zahozování všech bitů cílové hodnoty kromě jejích nejnižších 8 nebo 16 bitů. Zachované bity jsou interpretovány jako hodnoty se znaménkem pro sbyte a short a jako hodnoty bez znaménka pro byte, ushort a char. Výsledky pro char jsou zobrazeny číselně.
| Převést na | Hodnota x |
Zachování nízkých bitů | Příklad předchozího výsledku |
|---|---|---|---|
sbyte nebo byte |
298 | 0x2A |
42 |
sbyte |
-298 | 0xD6 |
-42 |
byte |
-42 | 0xD6 |
214 |
short, ushort nebo char |
65578 | 0x002A |
42 |
short |
-65578 | 0xFFD6 |
-42 |
ushort nebo char |
-42 | 0xFFD6 |
65494 |
Například následující kód by mohl vrátit 42:
static short ConvertValue(double value)
{
return unchecked((short)value);
}
short result = ConvertValue(65578.0);
Mezilehlý int je 65578 (0x0001002A). Při zachování pouze dolních 16 bitů je výsledkem 42 (0x002A), nikoli saturace na short.MaxValue.
Nové chování
Od .NET 11 se konverze v kontextu unchecked omezí na hranice cílového typu. Konečné hodnoty v cílovém rozsahu se budou dál zaokrouhlovat směrem k nule.
NaN převede na nulu.
| Převést na | Pod minimální hodnotou, včetně záporného nekonečna | Nad maximální hodnotou včetně kladného nekonečna | NaN |
|---|---|---|---|
sbyte |
-128 (sbyte.MinValue) |
127 (sbyte.MaxValue) |
0 |
byte |
0 (byte.MinValue) |
255 (byte.MaxValue) |
0 |
short |
-32768 (short.MinValue) |
32767 (short.MaxValue) |
0 |
ushort |
0 (ushort.MinValue) |
65535 (ushort.MaxValue) |
0 |
char |
0 (char.MinValue) |
65535 (char.MaxValue) |
0 |
Předchozí příklad nyní vrátí 32767 (short.MaxValue) místo 42. Podobně nyní převod z -42 na ushort vrací 0 místo 65494 a převod z 42 na 255 nyní vrací byte místo 298.
Protože převádějí přes float, odpovídající nekontrolované převody z Half také používají nové chování.
ConvertToInteger<TInteger>(Single) a ConvertToInteger<TInteger>(Double) se nyní u těchto malých cílových typů správně saturují.
Kontrolované konverze zůstávají beze změny a nadále vyvolávají OverflowException, pokud při konverzi dojde k přetečení. Tato změna nemění celočíselné převody na celé číslo ani širší celočíselné a vektorové převody, na které se vztahuje změna .NET 9.
Typ zásadní změny
Tato změna je změna chování.
Důvod změny
Změna v .NET 9 zavedla saturující chování pro převody na širší celočíselné typy, ale převody na 8bitové a 16bitové cílové typy stále vykazovaly u hodnot mimo rozsah a NaN chování závislé na hardwaru a implementaci. Tato změna zajišťuje u těchto převodů deterministické saturační chování a sjednocuje předem inicializované hodnoty mezi JIT, interpretem CoreCLR a Native AOT.
Doporučená akce
Pokud váš kód spoléhá u vstupů mimo rozsah na dosavadní výsledky, upravte ho tak, aby tam, kde je to možné, počítal se saturací na mezních hodnotách cílového typu.
Pokud potřebujete chování nativní pro platformu, které se před těmito změnami běžně používá, nejjednodušší alternativní řešení je ConvertToIntegerNative<TInteger>(Single) nebo ConvertToIntegerNative<TInteger>(Double). Například nahraďte přímé přetypování (ushort)x výrazem double.ConvertToIntegerNative<ushort>(x), když je x typu double, nebo výrazem float.ConvertToIntegerNative<ushort>(x), když je typu float.
Můžete také výslovně vybrat mezilehlý převod. Následující příklady používají double vstup x a ushort cíl:
| Požadované chování | Conversion |
|---|---|
| Nativní převod pro platformu na cílový typ, který obvykle obnovuje dřívější chování | double.ConvertToIntegerNative<ushort>(x) |
Saturace do int, poté zúžení, což odpovídá běžné sekvenci v CoreCLR pro .NET 9 a .NET 10 |
unchecked((ushort)(int)x) |
Nativní převod pro platformu na int, poté zúžení, což odpovídá běžné posloupnosti používané před .NET 9 |
unchecked((ushort)double.ConvertToIntegerNative<int>(x)) |
Použijte float.ConvertToIntegerNative pro float vstupy a nahraďte příslušný typ cíle pro sbyte, byte, shortnebo char.
Stejně jako u změny .NET 9, ConvertToIntegerNativenení zaručeno zachování předchozích výsledků pro hodnoty mimo rozsah nebo NaN. Vybere chování, které je efektivní pro aktuální platformu, které se může měnit napříč moduly runtime, architekturami nebo revizemi hardwaru. Explicitní (ushort)(int)x místo toho vybere saturační převod na int, po němž následuje zúžení na celočíselný typ; neobnoví chování všech historických implementací.
Pokud se převedená hodnota používá jako index pole, posun vyrovnávací paměti nebo délka, ověřte, že výsledná hodnota je v požadovaných mezích. To, že převod na jednom počítači vede k použitelné hodnotě, ještě neznamená, že k ní povede i nativní převod platformy na jiném.
Ovlivněná rozhraní API
- Nekontrolované explicitní přetypování z Single nebo Double na SByte, Byte, Int16, UInt16 nebo Char.
- Half nezaškrtnuté explicitní operátory převodu:
-
ConvertToInteger<TInteger>(Single) když
TIntegerje SByte, , Byte, Int16, UInt16nebo Char. -
ConvertToInteger<TInteger>(Double) když
TIntegerje SByte, , Byte, Int16, UInt16nebo Char.