Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Nota
Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.
Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze vengono acquisite nelle note
Ulteriori informazioni sul processo di adozione degli speclet delle funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche di .
Problema del campione: https://github.com/dotnet/csharplang/issues/6065
Sommario
Si tratta di una revisione della funzionalità iniziale dei numeri interi nativi (specifica), in cui i tipi di nint/nuint erano distinti dai tipi sottostanti System.IntPtr/System.UIntPtr.
In breve, ora trattiamo nint/nuint come semplici tipi alias di System.IntPtr/System.UIntPtr, come facciamo per int in relazione a System.Int32. Il flag di funzionalità di runtime System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr attiva questo nuovo comportamento.
Disegno
8.3.5 Tipi semplici
C# fornisce un set di tipi di struct predefiniti denominati tipi semplici. I tipi semplici vengono identificati tramite parole chiave, ma queste parole chiave sono semplicemente alias per i tipi di struct predefiniti nello spazio dei nomi System, come descritto nella tabella seguente.
| parola-chiave | tipo con alias |
|---|---|
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 Tipi integrali
C# supporta undici tipi integrali: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulonge char. [...]
8.8 Tipi non gestiti
In altre parole, un unmanaged_type è uno dei seguenti:
-
sbyte,byte,short,ushort,int,uint, ,nint,nuint,,long,ulong,char,float,double,decimalobool. - Qualsiasi enum_type.
- Qualsiasi struct_type definita dall'utente che non è un tipo composto e contiene solo campi di unmanaged_type.
- Nel codice non sicuro, qualsiasi pointer_type.
10.2.3 Conversioni numeriche implicite
Le conversioni numeriche implicite sono:
- Da
sbyteashort,int,nint,long,float,doubleodecimal. - Da
byteashort,ushort,int,uint,nint,nuint,long,ulong,float,doubleodecimal. - Da
shortaint,nint,long,float,doubleodecimal. - Da
ushortaint,uint,nint,nuint,long,ulong,float,doubleodecimal. - Da
intanint,long,float,doubleodecimal. - Da
uintanuint,long,ulong,float,doubleodecimal. -
Da
nintalong,float,doubleodecimal. -
Da
nuintaulong,float,doubleodecimal. - Da
longafloat,doubleodecimal. - Da
ulongafloat,doubleodecimal. - Da
charaushort,int,uint,nint,nuint,long,ulong,float,doubleodecimal. - Da
floatadouble.
[...]
10.2.11 Conversioni implicite di espressioni costanti
Una conversione implicita di espressioni costanti consente le conversioni seguenti:
- Un constant_expression di tipo
intpuò essere convertito nel tiposbyte,byte,short,ushort,uint,nint,nuintoulong, purché il valore del constant_expression sia compreso nell'intervallo del tipo di destinazione. [...]
10.3.2 Conversioni numeriche esplicite
Le conversioni numeriche esplicite sono le conversioni da un numeric_type a un'altra numeric_type per cui non esiste già una conversione numerica implicita:
- Da
sbyteabyte,ushort,uint,nuint,ulongochar. - Da
byteasbyteochar. - Da
shortasbyte,byte,ushort,uint,nuint,ulongochar. - Da
ushortasbyte,byte,shortochar. - Da
intasbyte,byte,short,ushort,uint,nuint,ulongochar. - Da
uintasbyte,byte,short,ushort,int,nintochar. - Da
longasbyte,byte,short,ushort,int,uint, ,nint,nuint,,ulongochar. -
Da
nintasbyte,byte,short,ushort,int,uint,nuint,ulongochar. -
Da
nuintasbyte,byte,short,ushort,int,uint,nint,longochar. - Da
ulongasbyte,byte,short,ushort,int,uint, ,nint,nuint,,longochar. - Da
charasbyte,byteoshort. - Da
floatasbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,charodecimal. - Da
doubleasbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,floatodecimal. - Da
decimalasbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,floatodouble.
[...]
10.3.3 Conversioni esplicite di enumerazione
Le conversioni esplicite di enumerazione sono:
- Da
sbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,float,doubleodecimala qualsiasi enum_type. - Da qualsiasi enum_type a
sbyte,byte,short,ushort,int,uint,nint,nuint,long,ulong,char,float,doubleodecimal. - Da qualunque enum_type a qualunque altro enum_type.
12.6.4.7 Destinazione di conversione migliore
Dato due tipi T₁ e T₂, T₁ è una destinazione di conversione migliore rispetto a T₂ se uno dei blocchi seguenti:
- Esiste una conversione implicita da
T₁aT₂e non esiste alcuna conversione implicita daT₂aT₁ -
T₁èTask<S₁>,T₂èTask<S₂>eS₁è una destinazione di conversione migliore rispetto aS₂ -
T₁èS₁oS₁?in cuiS₁è un tipo integrale con segno eT₂èS₂oS₂?doveS₂è un tipo integrale senza segno. In particolare: [...]
12.8.12 Accesso all'elemento
[...] Il numero di espressioni nella argument_list deve essere uguale al rango del array_typee ogni espressione deve essere di tipo int, uint, nint, nuint, long, o ulong, o deve essere implicitamente convertibile in uno o più di questi tipi.
11.8.12.2 Accesso alla matrice
[...] Il numero di espressioni nella argument_list deve essere uguale al rango del array_typee ogni espressione deve essere di tipo int, uint, nint, nuint, long, o ulong, o deve essere implicitamente convertibile in uno o più di questi tipi.
[...] L'elaborazione in fase di esecuzione di un accesso di matrice alla forma P[A], dove P è un primary_no_array_creation_expression di un array_type e A è un argument_list, è costituita dai passaggi seguenti: [...]
- Le espressioni di indice del argument_list vengono valutate in ordine, da sinistra a destra. Dopo la valutazione di ogni espressione di indice, viene eseguita una conversione implicita in uno dei tipi seguenti:
int,uint,nint,nuint,long,ulong. Viene scelto il primo tipo in questo elenco per il quale esiste una conversione implicita. [...]
12.8.16 Operatori di incremento e decremento postfissi
La risoluzione dell'overload di un operatore unario viene applicata per selezionare una specifica implementazione dell'operatore. Esistono operatori predefiniti ++ e -- per i tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint,long, ulong, char, float, double, decimale qualsiasi tipo di enumerazione.
Operatore 12.9.2 Unary plus
Gli operatori unari più predefiniti sono:
...
nint operator +(nint x);
nuint operator +(nuint x);
12.9.3 Operatore unario meno
Gli operatori unari meno predefiniti sono:
Negazione integer:
... nint operator –(nint x);
12.8.16 Operatori di incremento e decremento postfissi
Esistono operatori predefiniti ++ e -- per i tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimale qualsiasi tipo di enumerazione.
11.7.19 Espressioni di valore predefinite
Inoltre, un default_value_expression è un'espressione costante se il tipo è uno dei tipi di valore seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, o qualsiasi tipo di enumerazione.
12.9.5 Operatore di complemento bit per bit
Gli operatori di complemento bit per bit predefiniti sono:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
12.9.6 Operatori di incremento e decremento del prefisso
Esistono operatori predefiniti ++ e -- per i tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimale qualsiasi tipo di enumerazione.
12.10 Operatori aritmetici
Operatore di moltiplicazione 12.10.2
Di seguito sono elencati gli operatori di moltiplicazione predefiniti. Tutti gli operatori calcolano il prodotto di x e y.
Moltiplicazione di numeri interi:
... nint operator *(nint x, nint y); nuint operator *(nuint x, nuint y);
Operatore di divisione 12.10.3
Di seguito sono elencati gli operatori di divisione predefiniti. Tutti gli operatori calcolano il quoziente di x e y.
Divisione integer:
... nint operator /(nint x, nint y); nuint operator /(nuint x, nuint y);
12.10.4 Operatore di resto
Di seguito sono elencati gli operatori di resto predefiniti. Tutti gli operatori calcolano il resto della divisione tra x e y.
Resto intero:
... nint operator %(nint x, nint y); nuint operator %(nuint x, nuint y);
12.10.5 Operatore di somma
Addizione di numeri interi:
... nint operator +(nint x, nint y); nuint operator +(nuint x, nuint y);
12.10.6 Operatore di sottrazione
Sottrazione integer:
... nint operator –(nint x, nint y); nuint operator –(nuint x, nuint y);
12.11 Operatori shift
Di seguito sono elencati gli operatori di spostamento predefiniti.
Sposta a sinistra:
... nint operator <<(nint x, int count); nuint operator <<(nuint x, int count);Sposta a destra
... nint operator >>(nint x, int count); nuint operator >>(nuint x, int count);L'operatore
>>spostaxa destra di un numero di bit calcolato come descritto di seguito.Quando
xè di tipoint,nintolong, i bit di ordine ridotto dixvengono rimossi, i bit rimanenti vengono spostati verso destra e le posizioni di bit vuote dell'ordine elevato vengono impostate su zero sexè non negativo e impostato su uno sexè negativo.Quando
xè di tipouint,nuintoulong, i bit di ordine ridotto dixvengono rimossi, i bit rimanenti vengono spostati verso destra e le posizioni dei bit vuoti dell'ordine elevato vengono impostate su zero.Spostamento senza segno a destra:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
Per gli operatori predefiniti, il numero di bit da spostare viene calcolato nel modo seguente: [...]
- Quando il tipo di
xènintonuint, il conteggio dello spostamento è determinato dai cinque bit meno significativi dicountsu una piattaforma a 32 bit, oppure dai sei bit meno significativi dicountsu una piattaforma a 64 bit.
12.12 Operatori relazionali e di test dei tipi
12.12.2 Operatori di confronto integer
Gli operatori di confronto integer predefiniti sono:
...
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 Operatori logici
12.12.2 Operatori logici Integer
Gli operatori logici integer predefiniti sono:
...
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 Espressioni costanti
Un'espressione costante può essere un tipo valore o un tipo riferimento. Se un'espressione costante è un tipo valore, deve essere uno dei tipi seguenti: sbyte, byte, short, ushort, int, uint, nint, nuint, long, ulong, char, float, double, decimal, bool, o qualsiasi tipo di enumerazione.
[...]
Una conversione implicita di espressioni costanti consente la conversione di un'espressione costante di tipo int in sbyte, byte, short, ushort, uint, nint, nuint, o ulong, purché il valore dell'espressione costante sia compreso nell'intervallo del tipo di destinazione.
17.4 Accesso agli elementi di un array
È possibile accedere agli elementi di matrice usando element_access espressioni del form A[I₁, I₂, ..., Iₓ], dove A è un'espressione di un tipo di matrice e ogni Iₑ è un'espressione di tipo int, uint, nint, nuint,long, ulongo può essere convertita in modo implicito in uno o più di questi tipi. Il risultato dell'accesso a un elemento di matrice è una variabile, ovvero l'elemento della matrice selezionato dagli indici.
23.5 Conversioni dei puntatori
23.5.1 Generale
[...]
Inoltre, in un contesto non sicuro, il set di conversioni esplicite disponibili viene esteso per includere le seguenti conversioni esplicite di puntatore:
- Da qualsiasi pointer_type a qualsiasi altro pointer_type.
- Da
sbyte,byte,short,ushort,int,uint, ,nint,nuint,,longoulonga qualsiasi pointer_type. - Da qualsiasi pointer_type a
sbyte,byte,short,ushort,int,uint,nint,nuint,longoulong.
23.6.4 Accesso all'elemento puntatore
In un accesso a un elemento puntatore del tipo P[E], P deve essere un'espressione di tipo puntatore diverso da void*e E deve essere un'espressione che può essere convertita in modo implicito in int, uint, nint, nuint,longo ulong.
23.6.7 Aritmetica del puntatore
In un contesto non sicuro, l'operatore + e l'operatore – possono essere applicati ai valori di tutti i tipi di puntatore tranne void*. Di conseguenza, per ogni tipo di puntatore T*, gli operatori seguenti vengono definiti in modo implicito:
[...]
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);
Data un'espressione P di un tipo puntatore T* e un'espressione N di tipo int, uint, nint, nuint,longo ulong, le espressioni P + N e N + P calcolano il valore del puntatore di tipo T* risultante dall'aggiunta di N * sizeof(T) all'indirizzo specificato da P. Analogamente, l'espressione P – N calcola il valore del puntatore di tipo T* risultante dalla sottrazione di N * sizeof(T) dall'indirizzo specificato da P.
Varie considerazioni
Modifiche di rilievo
Uno degli effetti principali di questo design è che System.IntPtr e System.UIntPtr ottengono alcuni operatori incorporati (conversioni, unari e binari).
Tali operatori includono gli operatori checked, il che significa che gli operatori seguenti su tali tipi ora genereranno un'eccezione in caso di overflow:
IntPtr + intIntPtr - intIntPtr -> intlong -> IntPtrvoid* -> IntPtr
Codifica dei metadati
Questo design significa che nint e nuint possono essere semplicemente generati come System.IntPtr e System.UIntPtr, senza l'uso di System.Runtime.CompilerServices.NativeIntegerAttribute.
Allo stesso modo, caricando i metadati, si può ignorare NativeIntegerAttribute.
C# feature specifications