Числовой IntPtr
Заметка
Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Она включает предлагаемые изменения спецификации, а также информацию, необходимую во время проектирования и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.
Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия отражены в соответствующих заседаниях, посвящённых проектированию языка (LDM).
Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .
Выпуск чемпиона: https://github.com/dotnet/csharplang/issues/6065
Сводка
Это редакция функции начальных собственных целых чисел (спецификации), где типы nint
/nuint
отличались от базовых типов System.IntPtr
/System.UIntPtr
.
Короче говоря, теперь мы рассматриваем nint
/nuint
как псевдонимы простых типов System.IntPtr
/System.UIntPtr
, подобно тому как мы делаем для int
относительно System.Int32
. Флаг функции среды выполнения System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
активирует это новое поведение.
Дизайн
8.3.5 Простые типы
C# предоставляет набор стандартных struct
типов, называемых простыми типами. Простые типы определяются с помощью ключевых слов, но эти ключевые слова являются просто псевдонимами для предопределенных типов struct
в пространстве имен System
, как описано в таблице ниже.
Ключевое слово | Псевдоним типа |
---|---|
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 Целочисленные типы
C# поддерживает одиннадцать целочисленных типов: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
и char
. [...]
8.8 Неуправляемые типы
Другими словами, unmanaged_type является одним из следующих:
-
sbyte
,byte
,short
ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
,double
,decimal
илиbool
. - Любая enum_type.
- Любая определяемая пользователем структура типа, которая не является сконструированным типом и содержит только поля типа unmanaged_type.
- В небезопасном коде любые pointer_type.
10.2.3 Неявные числовые преобразования
Неявные числовые преобразования:
- От
sbyte
доshort
,int
,nint
,long
,float
,double
илиdecimal
. - От
byte
доshort
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
double
илиdecimal
. - От
short
доint
,nint
,long
,float
,double
илиdecimal
. - От
ushort
доint
,uint
,nint
,nuint
,long
,ulong
,float
,double
илиdecimal
. - От
int
доnint
,long
,float
,double
илиdecimal
. - От
uint
доnuint
,long
,ulong
,float
,double
илиdecimal
. -
от
nint
доlong
,float
,double
илиdecimal
. -
от
nuint
доulong
,float
,double
илиdecimal
. - От
long
доfloat
,double
илиdecimal
. - От
ulong
доfloat
,double
илиdecimal
. - От
char
доushort
,int
,uint
,nint
,nuint
,long
,ulong
,float
,double
илиdecimal
. - От
float
доdouble
.
[...]
Преобразования неявных константных выражений 10.2.11
Неявное преобразование константного выражения позволяет выполнить следующие преобразования:
-
constant_expression типа
int
можно преобразовать в типsbyte
,byte
,short
,ushort
,uint
,nint
,nuint
илиulong
, если значение constant_expression находится в диапазоне целевого типа. [...]
10.3.2 Явные числовые преобразования
Явные числовые преобразования — это преобразования из numeric_type в другую numeric_type, для которой неявное числовое преобразование еще не существует:
- От
sbyte
доbyte
,ushort
,uint
,nuint
,ulong
илиchar
. - От
byte
доsbyte
илиchar
. - От
short
доsbyte
,byte
,ushort
,uint
,nuint
,ulong
илиchar
. - От
ushort
доsbyte
,byte
,short
илиchar
. - От
int
доsbyte
,byte
,short
,ushort
,uint
,nuint
,ulong
илиchar
. - От
uint
доsbyte
,byte
,short
,ushort
,int
,nint
илиchar
. - От
long
доsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,ulong
илиchar
. -
от
nint
доsbyte
,byte
,short
,ushort
,int
,uint
,nuint
,ulong
илиchar
. -
от
nuint
доsbyte
,byte
,short
,ushort
,int
,uint
,nint
,long
илиchar
. - От
ulong
доsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
илиchar
. - От
char
доsbyte
,byte
илиshort
. - От
float
доsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
илиdecimal
. - От
double
доsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
илиdecimal
. - От
decimal
доsbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
,ulong
,char
,float
илиdouble
.
[...]
10.3.3 Явные преобразования типов перечисления
Конкретные преобразования перечисления:
- От
sbyte
,byte
,short
,ushort
,int
,uint
, ,nint
,nuint
,,long
,ulong
,char
,float
,double
илиdecimal
в любое enum_type. - От любого enum_type до
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
long
,ulong
,char
,float
,double
илиdecimal
. - От любого enum_type до любого другого enum_type.
12.6.4.7 Лучший целевой объект преобразования
Учитывая два типа T₁
и T₂
, T₁
— это лучший целевой объект преобразования, чем T₂
, если выполняется одно из следующих условий:
- Неявное преобразование из
T₁
вT₂
существует и неявное преобразование изT₂
вT₁
не существует. -
T₁
- этоTask<S₁>
,T₂
- этоTask<S₂>
, иS₁
является более подходящей целью для преобразования, чемS₂
-
T₁
S₁
илиS₁?
, гдеS₁
является подписанным целочисленным типом,T₂
S₂
илиS₂?
, гдеS₂
является целочисленным типом без знака. В частности: [...]
12.8.12 Доступ к элементу
[...] Число выражений в argument_list должно совпадать с рангом array_type, а каждое выражение должно быть типом int
, uint
, nint
, nuint
, long
или ulong,
или неявно преобразовано в один или несколько этих типов.
Доступ к массиву 11.8.12.2
[...] Число выражений в argument_list должно совпадать с рангом array_type, а каждое выражение должно быть типом int
, uint
, nint
, nuint
, long
или ulong,
или неявно преобразовано в один или несколько этих типов.
[...] Обработка обращения к массиву формы P[A]
, где P
является primary_no_array_creation_expression типа array_type, а A
является argument_list, состоит из следующих шагов: [...]
- Выражения индекса argument_list вычисляются по порядку слева направо. После оценки каждого выражения индекса выполняется неявное преобразование в один из следующих типов:
int
,uint
,nint
,nuint
,long
,ulong
. Первый тип в этом списке, для которого существует неявное преобразование, выбирается. [...]
12.8.16 Операторы постфиксного инкремента и декремента
Разрешение перегрузки унарного оператора применяется для выбора конкретной реализации оператора. Стандартные операторы ++
и --
существуют для следующих типов: sbyte
, byte
, short
, ushort
, int
, uint
, ,nint
, nuint
,,long
, ulong
, char
, float
, double
, decimal
и любого типа перечисления.
Оператор 12.9.2 Unary plus
Стандартные унарные операторы плюс:
...
nint operator +(nint x);
nuint operator +(nuint x);
12.9.3 Оператор унарного минуса
Стандартные унарные операторы минус:
Целочисленное отрицание:
... nint operator –(nint x);
12.8.16 Операторы постфиксного инкремента и декремента
Стандартные операторы ++
и --
существуют для следующих типов: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
и любого типа перечисления.
Выражения значений по умолчанию 11.7.19
Кроме того, default_value_expression является константным выражением, если тип является одним из следующих типов значений: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
или любого типа перечисления.
Оператор дополнения 12.9.5 Bitwise
Стандартные операторы битового дополнения:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
12.9.6 Префиксные инкрементные и декрементные операторы
Стандартные операторы ++
и --
существуют для следующих типов: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
и любого типа перечисления.
12.10 Арифметические операторы
Оператор умножения 12.10.2
Ниже перечислены предопределенные операторы умножения. Все операторы вычисляют продукт x
и y
.
Целочисленное умножение:
... nint operator *(nint x, nint y); nuint operator *(nuint x, nuint y);
12.10.3 Оператор деления
Ниже перечислены предопределенные операторы деления. Все операторы вычисляют частное x
на y
.
Целочисленное деление
... nint operator /(nint x, nint y); nuint operator /(nuint x, nuint y);
Оператор остатка 12.10.4
Ниже перечислены предопределенные операторы остатка. Все операторы вычисляют оставшуюся часть деления между x
и y
.
Остаток целочисленного числа:
... nint operator %(nint x, nint y); nuint operator %(nuint x, nuint y);
Оператор сложения 12.10.5
Добавление целых чисел:
... nint operator +(nint x, nint y); nuint operator +(nuint x, nuint y);
12.10.6 Оператор вычитания
Вычитание целочисленного числа:
... nint operator –(nint x, nint y); nuint operator –(nuint x, nuint y);
Операторы сдвига 12.11
Ниже перечислены предопределенные операторы смены.
Сдвиг влево
... nint operator <<(nint x, int count); nuint operator <<(nuint x, int count);
Сдвиг вправо:
... nint operator >>(nint x, int count); nuint operator >>(nuint x, int count);
Оператор
>>
сдвигаетx
вправо на несколько битов, вычисляемых, как описано ниже.Если
x
имеет типint
,nint
илиlong
, то младшие битыx
удаляются, оставшиеся биты сдвигаются вправо, а старшие пустые позиции устанавливаются в ноль, еслиx
не является отрицательным, и устанавливаются в единицу, еслиx
отрицательное.Если
x
имеет типuint
,nuint
илиulong
, то биты с низким порядкомx
удаляются, остальные биты сдвигаются вправо, а пустые позиции с высоким порядком пустых битов равны нулю.Беззнаковый сдвиг вправо:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
Для предопределенных операторов число битов для смены вычисляется следующим образом: [...]
- Если тип
x
—nint
илиnuint
, число сдвигов определяется пятью младшими битамиcount
на 32-разрядной платформе или шестью младшими битамиcount
на 64-разрядной платформе.
Операторы реляционного и типового тестирования 12.12
Операторы сравнения целых чисел 12.12.2
Стандартные операторы сравнения целых чисел:
...
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
12.12.2 Целочисленные логические операторы
Стандартные логические операторы целого числа:
...
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 Константные выражения
Константное выражение может быть либо типом значения, либо ссылочным типом. Если константное выражение является типом значения, оно должно быть одним из следующих типов: sbyte
, byte
, short
, ushort
, int
, uint
, nint
, nuint
, long
, ulong
, char
, float
, double
, decimal
, bool,
или любого типа перечисления.
[...]
Преобразование неявного константного выражения позволяет преобразовать константное выражение типа int
в sbyte
, byte
, short
, ushort
, uint
, nint
, nuint
или ulong
, если значение константного выражения находится в диапазоне конечного типа.
Доступ к элементу массива 17.4
Доступ к элементам массива осуществляется с использованием element_access выражений в форме A[I₁, I₂, ..., Iₓ]
, где A
является выражением типа массива, а каждое Iₑ
— выражение типа int
, uint
, nint
, nuint
,long
, ulong
или может быть неявно преобразовано в один или несколько этих типов. Результатом доступа к элементу массива является переменная, а именно элемент массива, выбранный индексами.
23.5 Преобразования указателей
23.5.1 Общие
[...]
Кроме того, в небезопасном контексте набор доступных явных преобразований расширяется, чтобы включить следующие явные преобразования указателя:
- От любого указателя типа к любому другому указателю типа.
- От
sbyte
,byte
,short
,ushort
,int
,uint
, ,nint
,nuint
,long
илиulong
в любой pointer_type. - От любого pointer_type до
sbyte
,byte
,short
,ushort
,int
,uint
,nint
,nuint
,long
илиulong
.
Доступ к элементу указателя 23.6.4
[...] В доступе к элементу формы P[E]
P
должен быть выражением типа указателя, отличного от void*
, и E
должно быть выражением, которое может быть неявно преобразовано в int
, uint
, nint
, nuint
,long
или ulong
.
23.6.7 Арифметика указателей
В небезопасном контексте оператор +
и –
можно применять к значениям всех типов указателей, кроме void*
. Таким образом, для каждого типа указателя T*
неявно определены следующие операторы:
[...]
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);
Учитывая выражение P
типа указателя T*
и выражение N
типа int
, uint
, nint
, nuint
,long
или ulong
, выражения P + N
и N + P
вычисляют значение указателя типа T*
, которое приводит к добавлению N * sizeof(T)
в адрес, заданный P
. Аналогичным образом, выражение P – N
вычисляет значение указателя типа T*
, которое получается в результате вычитания N * sizeof(T)
из адреса, заданного P
.
Различные соображения
Серьезные изменения
Одним из основных последствий этого дизайна является то, что System.IntPtr
и System.UIntPtr
получают некоторые встроенные операторы (преобразования, унарные и двоичные).
К ним относятся операторы checked
, что означает, что следующие операторы для этих типов теперь будут вызываться при переполнении:
IntPtr + int
IntPtr - int
IntPtr -> int
long -> IntPtr
void* -> IntPtr
Кодировка метаданных
Это проектирование означает, что nint
и nuint
могут быть просто переданы как System.IntPtr
и System.UIntPtr
, без использования System.Runtime.CompilerServices.NativeIntegerAttribute
.
Аналогичным образом, при загрузке метаданных NativeIntegerAttribute
следует игнорировать.
C# feature specifications