Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
In .NET 11 vertonen niet-gecontroleerde drijvende-kommaconversies naar sbyte, byte, short, ushort en char nu verzadigingsgedrag bij de grenzen van het doeltype. Waarden die te klein of te groot zijn, worden respectievelijk ingesteld op de minimum- of maximumwaarde van het doeltype.
Deze wijziging bouwt voort op de .NET 9-wijziging in conversies van drijvende komma naar gehele getallen, waarbij conversies van float en double naar int, uint, long en ulong werden gestandaardiseerd. .NET 11 breidt de verzadiging uit naar 8- en 16-bits bestemmingen.
De wijziging is van toepassing op CoreCLR, met inbegrip van de interpreter en systeemeigen AOT. Mono is niet opgenomen in deze wijziging.
Zie dotnet/runtime#128604 voor meer informatie.
Geïntroduceerde versie
.NET 11 preview 7
Vorig gedrag
Voorheen garandeerde .NET het resultaat van een niet-gecontroleerde conversie van drijvende komma naar een geheel getal niet wanneer de waarde buiten het bereik van het doeltype viel of NaN was. Resultaten kunnen verschillen tussen runtime-implementaties, zoals CoreCLR en Mono, tussen architecturen, zoals x86, x64, Arm32, Arm64 en WebAssembly, en tussen hardware-instructiesets binnen een architectuur, zoals x87, SSE2, AVX en AVX-512.
De brekende wijziging in .NET 9 belichtte specifiek x86 en x64, waarbij conversies bij overflow vaak sentinel-waarden retourneerden. Arm64 gebruikte al verzadigingsconversies volgens conventie. De wijziging standaardiseerde conversies naar de bredere integertypen, in plaats van de oude sentinelresultaten vast te leggen als contractuele afspraak.
Voor kleine integrale typen was een gebruikelijke CoreCLR-conversiereeks in .NET 9 en .NET 10 een verzadigende conversie naar int, gevolgd door vernauwing naar het doeltype, waarbij de hoge bits werden verworpen. In deze reeks wordt het gedrag uitgelegd dat veel toepassingen hebben ervaren, maar het was geen gegarandeerd contract voor een direct zwevend komma naar een kleine integrale cast.
In de volgende tabel worden de resultaten van die tweestapssequentie weergegeven voor een runtimewaarde van float of doublex. Deze invoergegevens passen in int, dus de voorbeelden laten het effect zien van het weggooien van alle bits behalve de laagste 8 of 16 bits van de doelwaarde. De bewaarde bits worden geïnterpreteerd als ondertekend voor sbyte en short, en niet-ondertekend voor byte, ushorten char. Resultaten voor char worden numeriek weergegeven.
| Omzetten naar | Waarde van x |
Bewaarde laagste bits | Voorbeeld van vorig resultaat |
|---|---|---|---|
sbyte of byte |
298 | 0x2A |
42 |
sbyte |
-298 | 0xD6 |
-42 |
byte |
-42 | 0xD6 |
214 |
short, of ushortchar |
65578 | 0x002A |
42 |
short |
-65578 | 0xFFD6 |
-42 |
ushort of char |
-42 | 0xFFD6 |
65494 |
De volgende code kan bijvoorbeeld 42 retourneren:
static short ConvertValue(double value)
{
return unchecked((short)value);
}
short result = ConvertValue(65578.0);
Het tussenliggende int is 65578 (0x0001002A). Omdat alleen de lage 16 bits behouden blijven, is 42 het resultaat (0x002A) in plaats van verzadiging tot short.MaxValue.
Nieuw gedrag
Vanaf .NET 11 worden unchecked-conversies begrensd op de limieten van het doeltype. Eindige waarden binnen het doelinterval blijven afgerond in de richting van nul.
NaN wordt geconverteerd naar nul.
| Omzetten naar | Onder minimum, inclusief negatieve oneindigheid | Boven maximum, inclusief positieve oneindigheid | 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 |
Het voorgaande voorbeeld retourneert 32767 nu (short.MaxValue) in plaats van 42. Op dezelfde manier geeft een conversie van byte naar 255 nu 42 terug in plaats van -42, en geeft een conversie van ushort naar 0 nu 65494 terug in plaats van 298.
Omdat ze via float converteren, gebruiken de bijbehorende niet-gecontroleerde conversies van Half ook het nieuwe gedrag.
ConvertToInteger<TInteger>(Single) en ConvertToInteger<TInteger>(Double) satureren nu correct voor deze kleine doeltypen.
Gecontroleerde conversies zijn ongewijzigd en blijven OverflowException genereren wanneer er een overloop optreedt. Deze wijziging heeft geen invloed op vernauwende conversies van gehele getallen naar gehele getallen, noch op de bredere conversies van gehele getallen en vectoren waarop de wijziging in .NET 9 betrekking heeft.
Type van brekende verandering
Deze wijziging is een gedragswijziging.
Reden voor wijziging
De .NET 9-wijziging zorgde voor verzadigend gedrag bij conversies naar bredere integertypen, maar conversies naar doeltypen van 8 en 16 bits vertoonden nog steeds hardware- en implementatieafhankelijk gedrag voor waarden buiten het bereik en NaN. Deze wijziging geeft die conversies deterministisch, verzadigend gedrag en zorgt ervoor dat de JIT, de CoreCLR-interpreter en de vooraf geïnitialiseerde waarden van Native AOT overeenkomen.
Aanbevolen actie
Als uw code afhankelijk is van eerdere resultaten voor invoer buiten het bereik, werkt u deze bij om waar mogelijk verzadiging te verwachten op de grenzen van het doeltype.
Als u het systeemeigen gedrag van het platform nodig hebt dat vaak wordt gebruikt vóór deze wijzigingen, is ConvertToIntegerNative<TInteger>(Single) of ConvertToIntegerNative<TInteger>(Double)de eenvoudigste tijdelijke oplossing. Vervang bijvoorbeeld een directe (ushort)x cast door double.ConvertToIntegerNative<ushort>(x) wanneer x een double is, of float.ConvertToIntegerNative<ushort>(x) wanneer het een float is.
U kunt ook expliciet de tussenliggende conversie selecteren. In de volgende voorbeelden wordt een double invoer x en een ushort bestemming gebruikt:
| Vereist gedrag | Conversion |
|---|---|
| Platformeigen conversie naar het doeltype, dat meestal eerder gedrag herstelt | double.ConvertToIntegerNative<ushort>(x) |
Verzadiging tot int, daarna vernauwing, overeenkomend met de gebruikelijke .NET 9- en .NET 10-CoreCLR-sequentie |
unchecked((ushort)(int)x) |
Platformgebonden conversie naar int, gevolgd door vernauwing, wat overeenkomt met een gebruikelijke reeks van vóór .NET 9 |
unchecked((ushort)double.ConvertToIntegerNative<int>(x)) |
Gebruik float.ConvertToIntegerNative voor invoer van het type float en vervang door het juiste doeltype voor sbyte, byte, short of char.
Net als bij de wijziging in .NET 9 biedt ConvertToIntegerNativegeen garantie dat eerdere resultaten worden gereproduceerd voor waarden buiten het bereik of NaN. Het selecteert het gedrag dat efficiënt is voor het huidige platform, dat kan veranderen in runtimes, architecturen of hardwarerevisies. Een expliciete (ushort)(int)x selecteert in plaats daarvan een verzadigende conversie naar int, gevolgd door het vernauwen naar een geheel getal; het herstelt niet het gedrag van alle historische implementaties.
Als de geconverteerde waarde wordt gebruikt als matrixindex, bufferverschil of lengte, controleert u of de resulterende waarde binnen de vereiste grenzen valt. Een conversie die een bruikbare waarde op de ene computer produceert, stelt niet vast dat de platformeigen conversie dit op een andere computer zal doen.
Betreffende API's
- Niet-gecontroleerde expliciete casts van Single of Double naar SByte, Byte, Int16, UInt16 of Char.
- Half uitgeschakelde expliciete conversieoperators:
-
ConvertToInteger<TInteger>(Single) wanneer
TIntegeris SByte, Byte, Int16, UInt16 of Char. -
ConvertToInteger<TInteger>(Double) wanneer
TIntegerSByte, Byte, Int16, UInt16 of Char is.