Numerisk IntPtr
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
, ulong
och 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
,decimal
ellerbool
. - 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
sbyte
tillshort
,int
,nint
,long
,float
,double
ellerdecimal
. - Från
byte
tillshort
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
ellerdecimal
. - Från
short
tillint
,nint
,long
,float
,double
ellerdecimal
. - Från
ushort
tillint
,uint
,nint
,nuint
,long
,ulong
,float
,double
ellerdecimal
. - Från
int
tillnint
,long
,float
,double
ellerdecimal
. - Från
uint
tillnuint
,long
,ulong
,float
,double
ellerdecimal
. -
Från
nint
tilllong
,float
,double
ellerdecimal
. -
Från
nuint
tillulong
,float
,double
ellerdecimal
. - Från
long
tillfloat
,double
ellerdecimal
. - Från
ulong
tillfloat
,double
ellerdecimal
. - Från
char
tillushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
ellerdecimal
. - Från
float
tilldouble
.
[...]
10.2.11 Implicita konverteringar av konstanta uttryck
En implicit konvertering av konstanta uttryck tillåter följande konverteringar:
- En constant_expression av typen
int
kan konverteras till typensbyte
,byte
,short
,ushort
,uint
,nint
,nuint
ellerulong
, 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
sbyte
tillbyte
,ushort
,uint
,nuint
,ulong
ellerchar
. - Från
byte
tillsbyte
ellerchar
. - Från
short
tillsbyte
,byte
,ushort
,uint
,nuint
,ulong
ellerchar
. - Från
ushort
tillsbyte
,byte
,short
ellerchar
. - Från
int
tillsbyte
,byte
,short
,ushort
,uint
,nuint
,ulong
ellerchar
. - Från
uint
tillsbyte
,byte
,short
,ushort
,int
,nint
ellerchar
. - Från
long
tillsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,ulong
ellerchar
. -
Från
nint
tillsbyte
,byte
,short
,ushort
,int
,uint
,nuint
,ulong
ellerchar
. -
Från
nuint
tillsbyte
,byte
,short
,ushort
,int
,uint
,nint
,long
ellerchar
. - Från
ulong
tillsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
ellerchar
. - Från
char
tillsbyte
,byte
ellershort
. - Från
float
tillsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
ellerdecimal
. - Från
double
tillsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
ellerdecimal
. - Från
decimal
tillsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
ellerdouble
.
[...]
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
,double
ellerdecimal
till alla enum_type. - Från alla enum_type till
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
ellerdecimal
. - 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
, decimal
och 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
, decimal
och 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
, decimal
och 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
>>
skiftarx
rätt med ett antal bitar som beräknas enligt beskrivningen nedan.När
x
är av typenint
,nint
ellerlong
, 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
,nuint
ellerulong
ignoreras 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
ärnint
ellernuint
, bestäms skiftantalet av de fem lägsta bitarna avcount
på en 32-bitarsplattform, eller av de sex lägsta bitarna avcount
på 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
, ulong
eller 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
,long
ellerulong
till alla pointer_type. - Från alla pointer_type till
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
ellerulong
.
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
,long
eller 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
,long
eller 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 + int
IntPtr - int
IntPtr -> int
long -> IntPtr
void* -> 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