Numerisches IntPtr
Hinweis
Dieser Artikel ist eine Feature-Spezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.
Es kann einige Abweichungen zwischen der Feature-Spezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den relevanten Anmerkungen zum Language Design Meeting (LDM) erfasst.
Weitere Informationen zur Einführung von Funktionen in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.
Champion-Problem: https://github.com/dotnet/csharplang/issues/6065
Zusammenfassung
Dies ist eine Änderung der ursprünglichen nativen Ganzzahlfunktion (Spezifikation), in der sich die nint
/nuint
-Typen von den zugrunde liegenden Typen System.IntPtr
/System.UIntPtr
unterschieden haben.
Kurz gesagt behandeln wir nint
/nuint
als einfache Typenaliase für System.IntPtr
/System.UIntPtr
, wie bei int
in Bezug auf System.Int32
. Das Laufzeitfunktions-Flag System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
löst dieses neue Verhalten aus.
Design
8.3.5 Einfache Typen
C# stellt eine Reihe vordefinierter struct
-Typen bereit, die einfache Typen genannt werden. Die einfachen Typen werden durch Schlüsselwörter identifiziert. Diese Schlüsselwörter sind jedoch einfach Aliase für vordefinierte struct
-Typen im System
-Namespace, wie in der folgenden Tabelle beschrieben.
Schlüsselwort | 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 Integrale Typen
C# unterstützt elf integrale Typen: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
und char
. [...]
8.8 Nicht verwaltete Typen
Anders ausgedrückt bedeutet dies, dass es sich bei einem unmanaged_type um einen der folgenden Typen handelt:
sbyte
,byte
,short
,ushort
,int
,uint
, ,nint
,nuint
,,long
,ulong
,char
,float
,double
,decimal
oderbool
.- Ein enum_type.
- Ein benutzerdefinierter struct_type, der nicht konstruiert ist und nur unmanaged_type-Felder enthält.
- In unsicherem Code ein .
10.2.3 Implizite numerische Konvertierungen
Die impliziten numerischen Konvertierungen sind:
- Von
sbyte
inshort
,int
,nint
,long
,float
,double
oderdecimal
. - Von
byte
inshort
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
oderdecimal
. - Von
short
inint
,nint
,long
,float
,double
oderdecimal
. - Von
ushort
inint
,uint
,nint
,nuint
,long
,ulong
,float
,double
oderdecimal
. - Von
int
innint
,long
,float
,double
oderdecimal
. - Von
uint
innuint
,long
,ulong
,float
,double
oderdecimal
. - Von
nint
inlong
,float
,double
oderdecimal
. - Von
nuint
inulong
,float
,double
oderdecimal
. - Von
long
infloat
,double
oderdecimal
. - Von
ulong
infloat
,double
oderdecimal
. - Von
char
inushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
oderdecimal
. - Von
float
bisdouble
.
[...]
10.2.11 Implizite Konvertierungen von Konstantenausdrücken
Eine implizite Konvertierung von Konstantenausdrücken ermöglicht die folgenden Konvertierungen:
- Ein constant_expression mit dem Typ
int
kann in den Typsbyte
,byte
,short
,ushort
,uint
,nint
,nuint
oderulong
konvertiert werden, wenn der Wert von constant_expression innerhalb des Bereichs des Zieltyps liegt. [...]
10.3.2 Explizite numerische Konvertierungen
Die expliziten numerischen Konvertierungen sind Konvertierungen aus einem numeric_type in einen anderen numeric_type, für die noch keine implizite numerische Konvertierung vorhanden ist:
- Von
sbyte
inbyte
,ushort
,uint
,nuint
,ulong
oderchar
. - Von
byte
insbyte
oderchar
. - Von
short
insbyte
,byte
,ushort
,uint
,nuint
,ulong
oderchar
. - Von
ushort
insbyte
,byte
,short
oderchar
. - Von
int
insbyte
,byte
,short
,ushort
,uint
,nuint
,ulong
oderchar
. - Von
uint
insbyte
,byte
,short
,ushort
,int
,nint
oderchar
. - Von
long
insbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,ulong
oderchar
. - Von
nint
insbyte
,byte
,short
,ushort
,int
,uint
,nuint
,ulong
oderchar
. - Von
nuint
insbyte
,byte
,short
,ushort
,int
,uint
,nint
,long
oderchar
. - Von
ulong
insbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
oderchar
. - Von
char
insbyte
,byte
odershort
. - Von
float
insbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
oderdecimal
. - Von
double
insbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
oderdecimal
. - Von
decimal
insbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
oderdouble
.
[...]
10.3.3 Explizite Enumerationskonvertierungen
Die expliziten Enumerationskonvertierungen sind:
- Von
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
oderdecimal
in einen enum_type. - Von einem enum_type in
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
oderdecimal
. - Von einem enum_type in einen anderen enum_type.
12.6.4.7 Besseres Konvertierungsziel
Bei den beiden Typen T₁
und T₂
ist T₁
ein besseres Konvertierungsziel als T₂
, wenn eine der folgenden Bedingungen erfüllt ist:
- Eine implizite Konversion von
T₁
nachT₂
existiert und keine implizite Konversion vonT₂
nachT₁
existiert -
T₁
istTask<S₁>
,T₂
istTask<S₂>
, undS₁
ist ein besseres Konvertierungsziel alsS₂
-
T₁
istS₁
oderS₁?
, wobeiS₁
ein Integraltypen mit Vorzeichen ist, undT₂
istS₂
oderS₂?
, wobeiS₂
ein Integraltypen ohne Vorzeichen ist. Insbesondere: [...]
12.8.12 Elementzugriff
[...] Die Anzahl der Ausdrücke in der argument_list muss dem Rang des array_type entsprechen und jeder Ausdruck muss vom Typ int
, uint
, nint
, nuint
, long
oder ulong,
sein oder implizit in einen oder mehrere dieser Typen konvertierbar sein.
11.8.12.2 Arrayzugriff
[...] Die Anzahl der Ausdrücke in der argument_list muss dem Rang des array_type entsprechen und jeder Ausdruck muss vom Typ int
, uint
, nint
, nuint
, long
oder ulong,
sein oder implizit in einen oder mehrere dieser Typen konvertierbar sein.
[...] Die Laufzeitverarbeitung eines Arrayzugriffs der Form P[A]
, wobei P
ein primary_no_array_creation_expression eines array_type ist und A
eine argument_list ist, umfasst die folgenden Schritte: [...]
- Die Indexausdrücke der argument_list werden von links nach rechts ausgewertet. Nach der Auswertung jedes Indexausdrucks erfolgt eine implizite Konvertierung in einen der folgenden Typen:
int
,uint
,nint
,nuint
,long
,ulong
. Der erste Typ in dieser Liste, für den eine implizite Konversion existiert, wird ausgewählt. [...]
12.8.16 Inkrementierungs- und Dekrementierungsoperatoren in Postfixnotation
Die unäre Operatorüberladungsauflösung wird angewendet, um eine bestimmte Operatorimplementierung auszuwählen. Es gibt vordefinierte ++
- und --
-Operatoren für die folgenden Typen: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
,long
, ulong
, char
, float
, double
, decimal
und alle Enumerationstypen.
12.9.2 Unärer Plus-Operator
Die vordefinierten unären Plus-Operatoren sind:
...
nint operator +(nint x);
nuint operator +(nuint x);
12.9.3 Unärer Minus-Operator
Die vordefinierten unären Minus-Operatoren sind:
Ganzzahlnegation:
... nint operator –(nint x);
12.8.16 Inkrementierungs- und Dekrementierungsoperatoren in Postfixnotation
Es gibt vordefinierte ++
- und --
-Operatoren für die folgenden Typen: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
und alle Enumerationstypen.
11.7.19 Ausdrücke für Standardwerte
Darüber hinaus ist ein default_value_expression ein konstanter Ausdruck, wenn der Typ einer der folgenden Werttypen ist: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
oder ein Enumerationstyp.
12.9.5 Bitweiser Komplement-Operator
Die vordefinierten bitweisen Komplement-Operatoren sind:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
12.9.6 Inkrementierungs- und Dekrementierungsoperatoren in Präfixnotation
Es gibt vordefinierte ++
- und --
-Operatoren für die folgenden Typen: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
und alle Enumerationstypen.
12.10 Arithmetische Operatoren
12.10.2 Multiplikations-Operator
Die vordefinierten Multiplikationsoperatoren sind im Folgenden aufgeführt. Die Operatoren berechnen alle das Produkt von x
und y
.
Ganzzahlmultiplikation:
... nint operator *(nint x, nint y); nuint operator *(nuint x, nuint y);
12.10.3 Divisions-Operator
Die vordefinierten Divisionsoperatoren sind unten aufgeführt. Alle Operatoren berechnen den Quotienten von x
und y
.
Ganzzahldivision:
... nint operator /(nint x, nint y); nuint operator /(nuint x, nuint y);
12.10.4 Rest-Operator
Die vordefinierten Rest-Operatoren werden unten aufgeführt. Alle Operatoren berechnen den Rest der Division zwischen x
und y
.
Ganzzahlrest:
... nint operator %(nint x, nint y); nuint operator %(nuint x, nuint y);
12.10.5 Additions-Operator
Ganzzahladdition:
... nint operator +(nint x, nint y); nuint operator +(nuint x, nuint y);
12.10.6 Subtraktions-Operator
Ganzzahlsubtraktion:
... nint operator –(nint x, nint y); nuint operator –(nuint x, nuint y);
12.11 Schiebeoperatoren
Die vordefinierten Verschiebungsoperatoren sind unten aufgeführt.
Nach links verschieben:
... nint operator <<(nint x, int count); nuint operator <<(nuint x, int count);
Nach rechts verschieben:
... nint operator >>(nint x, int count); nuint operator >>(nuint x, int count);
Der
>>
-Operator verschiebtx
um eine Anzahl von Bits nach rechts, die wie unten beschrieben berechnet wird.Wenn
x
vom Typint
,nint
oderlong
ist, werden die Bits mit niedriger Reihenfolge vonx
verworfen, die verbleibenden Bits werden nach rechts verschoben, und die leeren Bitpositionen in hoher Reihenfolge werden auf Null festgelegt, wennx
nicht negativ ist, und auf Eins festgelegt, wennx
negativ ist.Wenn
x
vom Typuint
,nuint
oderulong
ist, werden die niederwertigsten Bits vonx
verworfen, die verbleibenden Bits werden nach rechts verschoben, und die höchstwertigen leeren Bitpositionen werden auf Null gesetzt.Vorzeichenlose Rechtsverschiebung:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
Für die vordefinierten Operatoren wird die Anzahl der zu verschiebenden Bits wie folgt berechnet: [...]
- Wenn der Typ von
x
nint
odernuint
ist, wird der Verschiebungswert durch die niederwertigen fünf Bits voncount
auf einer 32-Bit-Plattform oder die niederwertigen sechs Bits voncount
auf einer 64-Bit-Plattform angegeben.
12.12 Relationale und Typtest-Operatoren
12.12.2 Ganzzahlvergleichs-Operatoren
Die vordefinierten ganzzahligen Vergleichsoperatoren sind:
...
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 Logische Operatoren
12.12.2 Logische Ganzzahl-Operatoren
Die vordefinierten ganzzahligen logischen Operatoren sind:
...
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 Konstante Ausdrücke
Ein konstanter Ausdruck kann ein Werttyp oder ein Referenztyp sein. Wenn ein Konstantenausdruck ein Werttyp ist, muss es sich um einen der folgenden Typen handeln: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
oder einen Enumerationstyp.
[...]
Eine implizite Konversion von konstanten Ausdrücken erlaubt die Konvertierung eines konstanten Ausdrucks vom Typ int
in sbyte
, byte
, short
, ushort
, uint
, nint
, nuint
, oder ulong
, sofern der Wert des konstanten Ausdrucks im Bereich des Zieltyps liegt.
17.4 Zugriff auf Arrayelemente
Auf Arrayelemente wird mithilfe von element_access Ausdrücken im Format A[I₁, I₂, ..., Iₓ]
zugegriffen, wobei A
ein Ausdruck eines Arraytyps ist und Iₑ
jeweils ein Ausdruck mit dem Typ int
, uint
, nint
, nuint
,long
oder ulong
ist oder implizit in einen oder mehrere dieser Typen konvertiert werden kann. Das Ergebnis eines Zugriffs auf Arrayelemente ist eine Variable, und zwar das Arrayelement, das durch die Indizes ausgewählt wurde.
23.5 Zeigerkonvertierungen
23.5.1 Allgemein
[...]
Darüber hinaus wird der Satz verfügbarer expliziter Konvertierungen in einem unsicheren Kontext erweitert, sodass er die folgenden expliziten Zeigerkonvertierungen einschließt:
- Von einem pointer_type in einen anderen pointer_type.
- Von
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
oderulong
in einen pointer_type. - Von einem pointer_type in
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
oderulong
.
23.6.5. Zeigerelementzugriff
[...] Bei einem Zeigerelementzugriff auf das Formular P[E]
muss P
ein Ausdruck eines anderen Zeigertyps als void*
sein und E
muss ein Ausdruck sein, der implizit in int
, uint
, nint
, nuint
,long
oder ulong
konvertiert werden kann.
23.6.7 Zeigerarithmetik
In einem unsicheren Kontext können der +
-Operator und der –
-Operator auf Werte aller Zeigertypen angewendet werden, mit Ausnahme von void*
. Daher werden für jeden Zeigertyp T*
die folgenden Operatoren implizit definiert:
[...]
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);
Auf der Basis eines Ausdrucks P
eines Zeigertyps T*
und eines Ausdrucks N
mit dem Typ int
, uint
, nint
, nuint
,long
oder ulong
berechnen die Ausdrücke P + N
und N + P
den Zeigerwert des Typs T*
, der das Ergebnis der Addition von N * sizeof(T)
zu der Adresse ist, die von P
angegeben wird. Ähnlich berechnet der Ausdruck P – N
den Zeigerwert des Typs T*
, der das Ergebnis der Subtraktion von N * sizeof(T)
von der Adresse ist, die von P
angegeben wird.
Verschiedene Überlegungen
Wichtige Änderungen
Eine der wichtigsten Auswirkungen dieses Designs ist, dass System.IntPtr
und System.UIntPtr
einige integrierte Operatoren (Konvertierungen, unär und binär) erhalten.
Dazu gehören checked
-Operatoren, was bedeutet, dass die folgenden Operatoren für diese Typen jetzt im Überlauf ausgelöst werden:
IntPtr + int
IntPtr - int
IntPtr -> int
long -> IntPtr
void* -> IntPtr
Codierung von Metadaten
Dieses Design bedeutet, dass nint
und nuint
einfach als System.IntPtr
und System.UIntPtr
ohne Verwendung von System.Runtime.CompilerServices.NativeIntegerAttribute
ausgegeben werden können.
Beim Laden von Metadaten kann NativeIntegerAttribute
jetzt ignoriert werden.
C# feature specifications