Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Notera
Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.
Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader dokumenteras i de relevanta anteckningarna från LDM (Language Design Meeting).
Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.
Champion-fråga: https://github.com/dotnet/csharplang/issues/6065
Sammanfattning
Det här är en revision av den ursprungliga funktionen för inbyggda heltal (spec), där de nint/nuint typerna skiljer sig från de underliggande typerna System.IntPtr/System.UIntPtr.
Kort och gott behandlar vi nu nint/nuint som enkla typer av alias System.IntPtr/System.UIntPtr, som vi gör för int i förhållande till System.Int32. Funktionsflaggan för körning System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr utlöser det här nya beteendet.
Design
8.3.5 Enkla typer
C# innehåller en uppsättning fördefinierade struct typer som kallas enkla typer. De enkla typerna identifieras via nyckelord, men de här nyckelorden är helt enkelt alias för fördefinierade struct typer i System namnområde enligt beskrivningen i tabellen nedan.
| nyckelord | aliastyp |
|---|---|
sbyte |
System.SByte |
byte |
System.Byte |
short |
System.Int16 |
ushort |
System.UInt16 |
int |
System.Int32 |
uint |
System.UInt32 |
nint |
System.IntPtr |
nuint |
System.UIntPtr |
long |
System.Int64 |
ulong |
System.UInt64 |
char |
System.Char |
float |
System.Single |
double |
System.Double |
bool |
System.Boolean |
decimal |
System.Decimal |
[...]
8.3.6 Integraltyper
C# stöder elva integraltyper: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulongoch char. [...]
8.8 Ohanterade typer
Med andra ord är en unmanaged_type något av följande:
-
sbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,float,double,decimalellerbool. - Vilken som helst enum_type.
- Alla användardefinierade struct_type som inte är en konstruerad typ och som innehåller fält av endast unmanaged_types.
- I osäker kod används valfri pekartyp pointer_type.
10.2.3 Implicita numeriska konverteringar
De implicita numeriska konverteringarna är:
- Från
sbytetillshort,int,nint,long,float,doubleellerdecimal. - Från
bytetillshort,ushort,int,uint,nint,nuint,long,ulong,float,doubleellerdecimal. - Från
shorttillint,nint,long,float,doubleellerdecimal. - Från
ushorttillint,uint,nint,nuint,long,ulong,float,doubleellerdecimal. - Från
inttillnint,long,float,doubleellerdecimal. - Från
uinttillnuint,long,ulong,float,doubleellerdecimal. -
Från
ninttilllong,float,doubleellerdecimal. -
Från
nuinttillulong,float,doubleellerdecimal. - Från
longtillfloat,doubleellerdecimal. - Från
ulongtillfloat,doubleellerdecimal. - Från
chartillushort,int,uint,nint,nuint,long,ulong,float,doubleellerdecimal. - Från
floattilldouble.
[...]
10.2.11 Implicita konverteringar av konstanta uttryck
En implicit konvertering av konstanta uttryck tillåter följande konverteringar:
- En constant_expression av typen
intkan konverteras till typensbyte,byte,short,ushort,uint,nint,nuintellerulong, förutsatt att värdet för constant_expression ligger inom måltypens intervall. [...]
10.3.2 Explicita numeriska konverteringar
Explicita numeriska konverteringar är konverteringar från en numeric_type till en annan numeric_type för vilka det inte redan finns någon implicit numerisk konvertering:
- Från
sbytetillbyte,ushort,uint,nuint,ulongellerchar. - Från
bytetillsbyteellerchar. - Från
shorttillsbyte,byte,ushort,uint,nuint,ulongellerchar. - Från
ushorttillsbyte,byte,shortellerchar. - Från
inttillsbyte,byte,short,ushort,uint,nuint,ulongellerchar. - Från
uinttillsbyte,byte,short,ushort,int,nintellerchar. - Från
longtillsbyte,byte,short,ushort,int,uint,nint,nuint,ulongellerchar. -
Från
ninttillsbyte,byte,short,ushort,int,uint,nuint,ulongellerchar. -
Från
nuinttillsbyte,byte,short,ushort,int,uint,nint,longellerchar. - Från
ulongtillsbyte,byte,short,ushort,int,uint,nint,nuint,longellerchar. - Från
chartillsbyte,byteellershort. - Från
floattillsbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,charellerdecimal. - Från
doubletillsbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,floatellerdecimal. - Från
decimaltillsbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,floatellerdouble.
[...]
10.3.3 Explicita uppräkningskonverteringar
De explicita uppräkningskonverteringarna är:
- Från
sbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,float,doubleellerdecimaltill alla enum_type. - Från alla enum_type till
sbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,float,doubleellerdecimal. - Från vilken som helst enum_type till vilken som helst annan enum_type.
12.6.4.7 Bättre konverteringsmål
Med två typer T₁ och T₂är T₁ ett bättre konverteringsmål än T₂ om något av följande gäller:
- Det finns en implicit konvertering från
T₁tillT₂och det finns ingen implicit konvertering frånT₂tillT₁ -
T₁ärTask<S₁>,T₂ärTask<S₂>, ochS₁är ett bättre konverteringsmål änS₂ -
T₁ärS₁ellerS₁?därS₁är en signerad integrerad typ ochT₂ärS₂ellerS₂?därS₂är en osignerad integrerad typ. Mer specifikt: [...]
12.8.12 Elementåtkomst
[...] Antalet uttryck i argument_list ska vara samma som rangordningen för array_type, och varje uttryck ska vara av typen int, uint, nint, nuint, long, eller ulong, eller ska implicit konverteras till en eller flera av dessa typer.
11.8.12.2 Matrisåtkomst
[...] Antalet uttryck i argument_list ska vara samma som rangordningen för array_type, och varje uttryck ska vara av typen int, uint, nint, nuint, long, eller ulong, eller ska implicit konverteras till en eller flera av dessa typer.
[...] Körningsbearbetningen av en matrisåtkomst för formuläret P[A], där P är en primary_no_array_creation_expression av en array_type och A är en argument_list, består av följande steg: [...]
- Indexuttrycken för argument_list utvärderas i ordning, från vänster till höger. Efter utvärdering av varje indexuttryck utförs en implicit konvertering till någon av följande typer:
int,uint,nint,nuint,long,ulong. Den första typen i den här listan som en implicit konvertering finns för väljs. [...]
12.8.16 Postfix-inkrements- och minskningsoperatorer
Unary operator overload resolution används för att välja en specifik operatorimplementering. Fördefinierade operatorer för ++ och -- finns för följande typer: sbyte, byte, short, ushort, int, uint, nint, nuint,long, ulong, char, float, double, decimaloch alla uppräkningstyper.
12.9.2 Unary plus operator
De fördefinierade unära plusoperatorerna är:
...
nint operator +(nint x);
nuint operator +(nuint x);
12.9.3 Unär minusoperator
De fördefinierade unary minus-operatorerna är:
Heltalsnegation
... nint operator –(nint x);
12.8.16 Postfix-inkrements- och minskningsoperatorer
Fördefinierade operatorer för ++ och -- finns för följande typer: sbyte, byte, short, ushort, int, uint, ,nint, nuint,, long, ulong, char, float, double, decimaloch alla enumtyper.
11.7.19 Standardvärdeuttryck
Dessutom är en default_value_expression ett konstant uttryck om typen är någon av följande värdetyper: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, eller någon uppräkningstyp.
12.9.5 Bitvis komplementoperator
De fördefinierade bitvis kompletterande operatorerna är:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
12.9.6 Inkrements- och minskningsoperatorer för prefix
Fördefinierade operatorer för ++ och -- finns för följande typer: sbyte, byte, short, ushort, int, uint, ,nint, nuint,, long, ulong, char, float, double, decimaloch alla enumtyper.
12.10 Aritmetiska operatorer
12.10.2 Multiplikationsoperator
De fördefinierade multiplikationsoperatorerna visas nedan. Operatorerna beräknar alla produkten av x och y.
Heltalsmultiplikation:
... nint operator *(nint x, nint y); nuint operator *(nuint x, nuint y);
12.10.3 Divisionsoperatör
De fördefinierade divisionsoperatorerna visas nedan. Operatorerna beräknar alla kvoten för x och y.
Heltalsdivision:
... nint operator /(nint x, nint y); nuint operator /(nuint x, nuint y);
12.10.4 Restoperator
De fördefinierade restoperatorerna visas nedan. Operatorerna beräknar resten av divisionen mellan x och y.
Heltalsrest:
... nint operator %(nint x, nint y); nuint operator %(nuint x, nuint y);
12.10.5 Additionsoperator
Heltalstillägg:
... nint operator +(nint x, nint y); nuint operator +(nuint x, nuint y);
12.10.6 Subtraktionsoperator
Heltalsundertraktion:
... nint operator –(nint x, nint y); nuint operator –(nuint x, nuint y);
12.11 Skiftoperatorer
De fördefinierade skiftoperatorerna visas nedan.
Skift vänster:
... nint operator <<(nint x, int count); nuint operator <<(nuint x, int count);Skift höger:
... nint operator >>(nint x, int count); nuint operator >>(nuint x, int count);Operatorn
>>skiftarxrätt med ett antal bitar som beräknas enligt beskrivningen nedan.När
xär av typenint,nintellerlong, ignorerasx:s lågordningsbitar, de återstående bitarna flyttas åt höger, och de tomma högordningsbitpositionerna ställs in på noll omxär icke-negativ och på ett omxär negativ.När
xär av typenuint,nuintellerulongignoreras de låga bitarna avx, de återstående bitarna flyttas åt höger och de tomma bitpositionerna i hög ordning är inställda på noll.Osignerat skift till höger:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
För de fördefinierade operatorerna beräknas antalet bitar som ska flyttas enligt följande: [...]
- När typen av
xärnintellernuint, bestäms skiftantalet av de fem lägsta bitarna avcountpå en 32-bitarsplattform, eller av de sex lägsta bitarna avcountpå en 64-bitarsplattform.
12.12 Relations- och typtestningsoperatorer
12.12.2 Jämförelseoperatorer för heltal
De fördefinierade heltalsjämförelseoperatorerna är:
...
bool operator ==(nint x, nint y);
bool operator ==(nuint x, nuint y);
bool operator !=(nint x, nint y);
bool operator !=(nuint x, nuint y);
bool operator <(nint x, nint y);
bool operator <(nuint x, nuint y);
bool operator >(nint x, nint y);
bool operator >(nuint x, nuint y);
bool operator <=(nint x, nint y);
bool operator <=(nuint x, nuint y);
bool operator >=(nint x, nint y);
bool operator >=(nuint x, nuint y);
12.12 Logiska operatorer
12.12.2 Heltalslogiska operatorer
De fördefinierade logiska heltalsoperatorerna är:
...
nint operator &(nint x, nint y);
nuint operator &(nuint x, nuint y);
nint operator |(nint x, nint y);
nuint operator |(nuint x, nuint y);
nint operator ^(nint x, nint y);
nuint operator ^(nuint x, nuint y);
12.22 Konstanta uttryck
Ett konstant uttryck kan vara antingen en värdetyp eller en referenstyp. Om ett konstant uttryck är en värdetyp måste det vara någon av följande typer: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, eller någon uppräkningstyp.
[...]
Med en implicit konvertering av konstanta uttryck kan ett konstant uttryck av typen int konverteras till sbyte, byte, short, ushort, uint, nint, nuint, eller ulong, förutsatt att värdet för det konstanta uttrycket ligger inom måltypens intervall.
17.4 Matriselementåtkomst
Matriselement används med hjälp av element_access uttryck i formuläret A[I₁, I₂, ..., Iₓ], där A är ett uttryck av en matristyp och varje Iₑ är ett uttryck av typen int, uint, nint, nuint,long, ulongeller implicit kan konverteras till en eller flera av dessa typer. Resultatet av en matriselementåtkomst är en variabel, nämligen matriselementet som väljs av indexen.
23.5 Pekarkonverteringar
23.5.1 Allmänt
[...]
I en osäker kontext utökas dessutom uppsättningen med tillgängliga explicita konverteringar till att omfatta följande explicita pekarkonverteringar:
- Från vilken som helst pointer_type till vilket som helst pointer_type.
- Från
sbyte,byte,short,ushort,int,uint,nint,nuint,longellerulongtill alla pointer_type. - Från alla pointer_type till
sbyte,byte,short,ushort,int,uint,nint,nuint,longellerulong.
23.6.4 Åtkomst till pekarelement
[...] I ett pekarelement för formuläret P[E]ska P vara ett uttryck av en annan pekartyp än void*och E ska vara ett uttryck som implicit kan konverteras till int, uint, nint, nuint,longeller ulong.
23.6.7 Pekare-aritmetik
I ett osäkert sammanhang kan operatorn + och – tillämpas på värden för alla pekartyper förutom void*. För varje pekartyp T*definieras följande operatorer implicit:
[...]
T* operator +(T* x, nint y);
T* operator +(T* x, nuint y);
T* operator +(nint x, T* y);
T* operator +(nuint x, T* y);
T* operator -(T* x, nint y);
T* operator -(T* x, nuint y);
Med ett uttryck P av en pekartyp T* och ett uttryck N av typen int, uint, nint, nuint,longeller ulong, beräknar uttrycken P + N och N + P pekarvärdet för typen T* som resulterar i att N * sizeof(T) läggs till i adressen som anges av P. På samma sätt beräknar uttrycket P – N pekarvärdet av typen T* som är resultatet av att subtrahera N * sizeof(T) från adressen som anges av P.
Olika överväganden
Icke-bakåtkompatibla ändringar
En av de viktigaste effekterna av den här designen är att System.IntPtr och System.UIntPtr får några inbyggda operatorer (konverteringar, unära och binära).
Dessa omfattar checked-operatörer, vilket innebär att följande operatörer på dessa typer nu kommer att utlösas vid överbelastning:
IntPtr + intIntPtr - intIntPtr -> intlong -> IntPtrvoid* -> IntPtr
Metadatakodning
Den här designen innebär att nint och nuint helt enkelt kan genereras som System.IntPtr och System.UIntPtr, utan att använda System.Runtime.CompilerServices.NativeIntegerAttribute.
På samma sätt kan NativeIntegerAttribute ignoreras när metadata läses in.
C# feature specifications