Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Nota
Artikel ini adalah spesifikasi fitur. Spesifikasi berfungsi sebagai dokumen desain untuk fitur tersebut. Ini termasuk perubahan spesifikasi yang diusulkan, bersama dengan informasi yang diperlukan selama desain dan pengembangan fitur. Artikel ini diterbitkan sampai perubahan spesifikasi yang diusulkan diselesaikan dan dimasukkan dalam spesifikasi ECMA saat ini.
Mungkin ada beberapa perbedaan antara spesifikasi fitur dan implementasi yang selesai. Perbedaan tersebut dicatat dalam catatan terkait rapat desain bahasa (LDM) .
Anda dapat mempelajari lebih lanjut tentang proses untuk mengadopsi speklet fitur ke dalam standar bahasa C# dalam artikel tentang spesifikasi .
Masalah juara: https://github.com/dotnet/csharplang/issues/435
Ringkasan
Dukungan bahasa untuk jenis bilangan bulat berukuran asli yang ditandatangani dan tidak ditandatangani.
Motivasinya adalah untuk skenario interoperabilitas dan untuk perpustakaan tingkat rendah.
Desain
Pengidentifikasi nint dan nuint adalah kata kunci kontekstual baru yang mewakili jenis bilangan bulat asli yang ditandatangani dan tidak ditandatangani.
Pengidentifikasi hanya diperlakukan sebagai kata kunci ketika pencarian nama tidak menemukan hasil yang layak di lokasi program tersebut.
nint x = 3;
_ = nint.Equals(x, 3);
Jenis nint dan nuint diwakili oleh jenis dasar System.IntPtr dan System.UIntPtr, dimana compiler menampilkan konversi dan operasi tambahan untuk jenis tersebut sebagai bilangan bulat asli.
Konstanta
Ekspresi konstanta mungkin berjenis nint atau nuint.
Tidak ada sintaks langsung untuk literal integer bawaan. Cast implisit atau eksplisit dari nilai konstanta integral lainnya dapat digunakan sebagai alternatif: const nint i = (nint)42;.
nint konstanta berada dalam rentang [ int.MinValue, int.MaxValue ].
nuint konstanta berada dalam rentang [ uint.MinValue, uint.MaxValue ].
Tidak ada bidang MinValue atau MaxValue pada nint atau nuint karena, selain nuint.MinValue, nilai-nilai tersebut tidak dapat dipancarkan sebagai konstanta.
Lipatan konstan didukung untuk semua operator unary { +, -, ~ } dan operator biner { +, -, *, /, %, ==, !=, <, <=, >, >=, &, |, ^, <<, >> }.
Operasi pelipatan konstan dievaluasi dengan operand Int32 dan UInt32 alih-alih integer asli agar memberikan perilaku yang konsisten terlepas dari platform pengkompilasi.
Jika operasi menghasilkan nilai konstanta dalam 32-bit, pelipatan konstan dilakukan pada waktu kompilasi.
Jika tidak, operasi dijalankan pada runtime dan tidak dianggap sebagai konstanta.
Konversi
Ada konversi identitas antara nint dan IntPtr, dan antara nuint dan UIntPtr.
Ada konversi identitas antara jenis gabungan yang berbeda hanya dengan inti asli dan jenis yang mendasari: array, Nullable<>, jenis terbangun, dan tuples.
Tabel di bawah ini mencakup konversi antara tipe khusus.
(IL untuk setiap konversi mencakup varian untuk konteks unchecked dan checked jika berbeda.)
Catatan umum pada tabel di bawah ini:
-
conv.uadalah perpanjangan nol ke integer asli danconv.iadalah perpanjangan tanda ke integer asli. - konteks
checkeduntuk pelebaran dan penyempitan adalah:-
conv.ovf.*untuksigned to * -
conv.ovf.*.ununtukunsigned to *
-
- konteks
uncheckeduntuk pelebaran adalah:-
conv.i*untuksigned to *(di mana * adalah lebar target) -
conv.u*untukunsigned to *(di mana * adalah lebar target)
-
-
uncheckedkonteks untuk penyempitan adalah:-
conv.i*untukany to signed *(di mana * adalah lebar target) -
conv.u*untukany to unsigned *(di mana * adalah lebar target)
-
Mengambil beberapa contoh:
-
sbyte to nintdansbyte to nuintmenggunakanconv.isaatbyte to nintdanbyte to nuintmenggunakanconv.ukarena semuanya melebar. -
nint to bytedannuint to bytemenggunakanconv.u1saatnint to sbytedannuint to sbytemenggunakanconv.i1. Untukbyte,sbyte,short, danushort, "jenis tumpukan" adalahint32. Jadi,conv.i1secara efektif "dikonversi turun ke byte bertanda dan kemudian diperluas tandanya hingga int32" sementaraconv.u1secara efektif "dikonversi turun ke byte tak bertanda dan kemudian diperluas dengan nol hingga int32". -
checked void* to nintmenggunakanconv.ovf.i.uncara yang sama sepertichecked void* to longmenggunakanconv.ovf.i8.un.
| Operand | Target | Konversi | IL |
|---|---|---|---|
object |
nint |
Unboxing | unbox |
void* |
nint |
PointerToVoid (Pointer ke Void) | nop / conv.ovf.i.un |
sbyte |
nint |
ImplisitNumerik | conv.i |
byte |
nint |
ImplisitNumerik | conv.u |
short |
nint |
ImplisitNumerik | conv.i |
ushort |
nint |
ImplisitNumerik | conv.u |
int |
nint |
ImplisitNumerik | conv.i |
uint |
nint |
ExplicitNumeric | conv.u / conv.ovf.i.un |
long |
nint |
ExplicitNumeric | conv.i / conv.ovf.i |
ulong |
nint |
ExplicitNumeric | conv.i / conv.ovf.i.un |
char |
nint |
ImplisitNumerik | conv.u |
float |
nint |
ExplicitNumeric | conv.i / conv.ovf.i |
double |
nint |
ExplicitNumeric | conv.i / conv.ovf.i |
decimal |
nint |
ExplicitNumeric | long decimal.op_Explicit(decimal) conv.i / ... conv.ovf.i |
IntPtr |
nint |
Identitas | |
UIntPtr |
nint |
Tidak | |
object |
nuint |
Unboxing | unbox |
void* |
nuint |
PointerToVoid (Pointer ke Void) | nop |
sbyte |
nuint |
ExplicitNumeric | conv.i / conv.ovf.u |
byte |
nuint |
ImplisitNumerik | conv.u |
short |
nuint |
ExplicitNumeric | conv.i / conv.ovf.u |
ushort |
nuint |
ImplisitNumerik | conv.u |
int |
nuint |
ExplicitNumeric | conv.i / conv.ovf.u |
uint |
nuint |
ImplisitNumerik | conv.u |
long |
nuint |
ExplicitNumeric | conv.u / conv.ovf.u |
ulong |
nuint |
ExplicitNumeric | conv.u / conv.ovf.u.un |
char |
nuint |
ImplisitNumerik | conv.u |
float |
nuint |
ExplicitNumeric | conv.u / conv.ovf.u |
double |
nuint |
ExplicitNumeric | conv.u / conv.ovf.u |
decimal |
nuint |
ExplicitNumeric | ulong decimal.op_Explicit(decimal) conv.u / ... conv.ovf.u.un |
IntPtr |
nuint |
Tidak | |
UIntPtr |
nuint |
Identitas | |
| Enumerasi | nint |
EnumerasiEksplisit (ExplicitEnumeration) | |
| Enumerasi | nuint |
EnumerasiEksplisit (ExplicitEnumeration) |
| Operand | Target | Konversi | IL |
|---|---|---|---|
nint |
object |
Tinju | box |
nint |
void* |
PointerToVoid (Pointer ke Void) | nop / conv.ovf.u |
nint |
nuint |
ExplicitNumeric |
conv.u (dapat dihilangkan) / conv.ovf.u |
nint |
sbyte |
ExplicitNumeric | conv.i1 / conv.ovf.i1 |
nint |
byte |
ExplicitNumeric | conv.u1 / conv.ovf.u1 |
nint |
short |
ExplicitNumeric | conv.i2 / conv.ovf.i2 |
nint |
ushort |
ExplicitNumeric | conv.u2 / conv.ovf.u2 |
nint |
int |
ExplicitNumeric | conv.i4 / conv.ovf.i4 |
nint |
uint |
ExplicitNumeric | conv.u4 / conv.ovf.u4 |
nint |
long |
ImplisitNumerik | conv.i8 |
nint |
ulong |
ExplicitNumeric | conv.i8 / conv.ovf.u8 |
nint |
char |
ExplicitNumeric | conv.u2 / conv.ovf.u2 |
nint |
float |
ImplisitNumerik | conv.r4 |
nint |
double |
ImplisitNumerik | conv.r8 |
nint |
decimal |
ImplisitNumerik | conv.i8 decimal decimal.op_Implicit(long) |
nint |
IntPtr |
Identitas | |
nint |
UIntPtr |
Tidak | |
nint |
Enumerasi | EnumerasiEksplisit (ExplicitEnumeration) | |
nuint |
object |
Tinju | box |
nuint |
void* |
PointerToVoid (Pointer ke Void) | nop |
nuint |
nint |
ExplicitNumeric |
conv.i(dapat dihilangkan) / conv.ovf.i.un |
nuint |
sbyte |
ExplicitNumeric | conv.i1 / conv.ovf.i1.un |
nuint |
byte |
ExplicitNumeric | conv.u1 / conv.ovf.u1.un |
nuint |
short |
ExplicitNumeric | conv.i2 / conv.ovf.i2.un |
nuint |
ushort |
ExplicitNumeric | conv.u2 / conv.ovf.u2.un |
nuint |
int |
ExplicitNumeric | conv.i4 / conv.ovf.i4.un |
nuint |
uint |
ExplicitNumeric | conv.u4 / conv.ovf.u4.un |
nuint |
long |
ExplicitNumeric | conv.u8 / conv.ovf.i8.un |
nuint |
ulong |
ImplisitNumerik | conv.u8 |
nuint |
char |
ExplicitNumeric | conv.u2 / conv.ovf.u2.un |
nuint |
float |
ImplisitNumerik | conv.r.un conv.r4 |
nuint |
double |
ImplisitNumerik | conv.r.un conv.r8 |
nuint |
decimal |
ImplisitNumerik | conv.u8 decimal decimal.op_Implicit(ulong) |
nuint |
IntPtr |
Tidak | |
nuint |
UIntPtr |
Identitas | |
nuint |
Enumerasi | EnumerasiEksplisit (ExplicitEnumeration) |
Konversi dari A ke Nullable<B> adalah:
- konversi implisit nullable jika ada konversi identitas atau konversi implisit dari
AkeB; - konversi bertipe nullable eksplisit jika terdapat konversi eksplisit dari
AkeB; - jika tidak, maka tidak valid
Konversi dari Nullable<A> ke B adalah:
- konversi eksplisit nullable jika ada konversi identitas atau konversi numerik implisit atau eksplisit dari
AkeB; - jika tidak, maka tidak valid
Konversi dari Nullable<A> ke Nullable<B> adalah:
- konversi identitas jika ada konversi identitas dari
AkeB; - konversi nullable eksplisit jika ada konversi numerik implisit atau eksplisit dari
AkeB; - jika tidak, maka tidak valid
Operator
Operator yang telah ditentukan sebelumnya adalah sebagai berikut.
Operator ini dipertimbangkan selama resolusi kelebihan beban berdasarkan aturan normal untuk konversi implisit jika setidaknya salah satu operand berjenis nint atau nuint.
(IL untuk setiap operator mencakup varian untuk konteks unchecked dan checked jika berbeda.)
| Unari | Tanda Tangan Operator | IL |
|---|---|---|
+ |
nint operator +(nint value) |
nop |
+ |
nuint operator +(nuint value) |
nop |
- |
nint operator -(nint value) |
neg |
~ |
nint operator ~(nint value) |
not |
~ |
nuint operator ~(nuint value) |
not |
| Biner | Tanda Tangan Operator | IL |
|---|---|---|
+ |
nint operator +(nint left, nint right) |
add / add.ovf |
+ |
nuint operator +(nuint left, nuint right) |
add / add.ovf.un |
- |
nint operator -(nint left, nint right) |
sub / sub.ovf |
- |
nuint operator -(nuint left, nuint right) |
sub / sub.ovf.un |
* |
nint operator *(nint left, nint right) |
mul / mul.ovf |
* |
nuint operator *(nuint left, nuint right) |
mul / mul.ovf.un |
/ |
nint operator /(nint left, nint right) |
div |
/ |
nuint operator /(nuint left, nuint right) |
div.un |
% |
nint operator %(nint left, nint right) |
rem |
% |
nuint operator %(nuint left, nuint right) |
rem.un |
== |
bool operator ==(nint left, nint right) |
beq / ceq |
== |
bool operator ==(nuint left, nuint right) |
beq / ceq |
!= |
bool operator !=(nint left, nint right) |
bne |
!= |
bool operator !=(nuint left, nuint right) |
bne |
< |
bool operator <(nint left, nint right) |
blt / clt |
< |
bool operator <(nuint left, nuint right) |
blt.un / clt.un |
<= |
bool operator <=(nint left, nint right) |
ble |
<= |
bool operator <=(nuint left, nuint right) |
ble.un |
> |
bool operator >(nint left, nint right) |
bgt / cgt |
> |
bool operator >(nuint left, nuint right) |
bgt.un / cgt.un |
>= |
bool operator >=(nint left, nint right) |
bge |
>= |
bool operator >=(nuint left, nuint right) |
bge.un |
& |
nint operator &(nint left, nint right) |
and |
& |
nuint operator &(nuint left, nuint right) |
and |
| |
nint operator |(nint left, nint right) |
or |
| |
nuint operator |(nuint left, nuint right) |
or |
^ |
nint operator ^(nint left, nint right) |
xor |
^ |
nuint operator ^(nuint left, nuint right) |
xor |
<< |
nint operator <<(nint left, int right) |
shl |
<< |
nuint operator <<(nuint left, int right) |
shl |
>> |
nint operator >>(nint left, int right) |
shr |
>> |
nuint operator >>(nuint left, int right) |
shr.un |
Untuk beberapa operator biner, operator IL mendukung jenis operand tambahan (lihat tabel jenis ECMA-335 III.1.5 Operand). Tetapi set jenis operand yang didukung oleh C# terbatas demi kesederhanaan dan untuk konsistensi dengan operator yang ada dalam bahasa ini.
Versi operator yang telah diangkat, dengan argumen dan jenis pengembalian berupa nint? dan nuint?, didukung.
Operasi penugasan gabungan x op= y di mana x atau y adalah int bawaan mengikuti aturan yang sama seperti jenis primitif lainnya dengan operator yang sudah ditetapkan.
Secara khusus ekspresi terikat sebagai x = (T)(x op y) di mana T adalah jenis x dan di mana x hanya dievaluasi sekali.
Operator shift harus menutupi jumlah bit yang akan digeser - ke 5 bit jika sizeof(nint) adalah 4, dan menjadi 6 bit jika sizeof(nint) adalah 8.
(lihat §12.11) dalam spesifikasi C#).
Pengkompilasi C#9 akan melaporkan kesalahan yang mengikat ke operator bilangan bulat asli yang telah ditentukan saat mengkompilasi dengan versi bahasa yang lebih lama, tetapi akan memungkinkan penggunaan konversi yang telah ditentukan sebelumnya ke dan dari bilangan bulat asli.
csc -langversion:9 -t:library A.cs
public class A
{
public static nint F;
}
csc -langversion:8 -r:A.dll B.cs
class B : A
{
static void Main()
{
F = F + 1; // error: nint operator+ not available with -langversion:8
F = (System.IntPtr)F + 1; // ok
}
}
Aritmatika penunjuk
Tidak ada operator yang telah ditentukan sebelumnya di C# untuk penambahan atau pengurangan pointer dengan offset bilangan bulat asli.
Sebagai gantinya, nilai nint dan nuint dipromosikan ke long dan ulong dan aritmatika pointer menggunakan operator yang telah ditentukan sebelumnya untuk jenis tersebut.
static T* AddLeftS(nint x, T* y) => x + y; // T* operator +(long left, T* right)
static T* AddLeftU(nuint x, T* y) => x + y; // T* operator +(ulong left, T* right)
static T* AddRightS(T* x, nint y) => x + y; // T* operator +(T* left, long right)
static T* AddRightU(T* x, nuint y) => x + y; // T* operator +(T* left, ulong right)
static T* SubRightS(T* x, nint y) => x - y; // T* operator -(T* left, long right)
static T* SubRightU(T* x, nuint y) => x - y; // T* operator -(T* left, ulong right)
Peningkatan numerik biner
promosi numerik biner teks informatif (lihat §12.4.7.3) dalam spesifikasi C# telah diperbarui sebagai berikut:
- …
- Jika tidak, jika salah satu operand berjenis
ulong, operand lain dikonversi ke jenisulong, atau kesalahan waktu pengikatan terjadi jika operand lain berjenissbyte,short,int,nint, ataulong.- Jika tidak, jika salah satu operand berjenis
nuint, operand lain dikonversi ke jenisnuint, atau kesalahan waktu pengikatan terjadi jika operand lain berjenissbyte,short,int,nint, ataulong.- Jika tidak, jika salah satu operan berjenis
long, operand lainnya dikonversi ke jenislong.- Jika tidak, jika salah satu operan berjenis
uintdan operand lainnya berjenissbyte,short,nint, atauint, kedua operan dikonversi ke jenislong.- Jika tidak, jika salah satu operan berjenis
uint, operand lainnya dikonversi ke jenisuint.- Jika tidak, jika salah satu operan berjenis
nint, operand lainnya dikonversi ke jenisnint.- Jika tidak, kedua operan dikonversi ke jenis
int.
Dinamis
Konversi dan operator disintesis oleh pengkompilasi dan bukan bagian dari jenis IntPtr dan UIntPtr yang mendasar.
Akibatnya, konversi dan operator tersebut tidak tersedia dari pengikat waktu proses untuk dynamic.
nint x = 2;
nint y = x + x; // ok
dynamic d = x;
nint z = d + x; // RuntimeBinderException: '+' cannot be applied 'System.IntPtr' and 'System.IntPtr'
Jenis anggota
Satu-satunya konstruktor untuk nint atau nuint adalah konstruktor tanpa parameter.
Anggota System.IntPtr dan System.UIntPtrberikut secara eksplisit dikecualikan dari nint atau nuint:
// constructors
// arithmetic operators
// implicit and explicit conversions
public static readonly IntPtr Zero; // use 0 instead
public static int Size { get; } // use sizeof() instead
public static IntPtr Add(IntPtr pointer, int offset);
public static IntPtr Subtract(IntPtr pointer, int offset);
public int ToInt32();
public long ToInt64();
public void* ToPointer();
Anggota System.IntPtr dan System.UIntPtryang tersisa secara implisit disertakan dalam dalam nint dan nuint. Untuk .NET Framework 4.7.2:
public override bool Equals(object obj);
public override int GetHashCode();
public override string ToString();
public string ToString(string format);
Antarmuka yang diimplementasikan oleh System.IntPtr dan System.UIntPtrsecara implisit disertakan dalam nint dan nuint, dengan kemunculan tipe dasar digantikan oleh tipe bilangan bulat asli yang sesuai.
Misalnya jika IntPtr menerapkan ISerializable, IEquatable<IntPtr>, IComparable<IntPtr>, maka nint menerapkan ISerializable, IEquatable<nint>, IComparable<nint>.
Mengambil alih, menyembunyikan, dan mengimplementasikan
nint dan System.IntPtr, dan nuint dan System.UIntPtr, dianggap setara untuk mengambil alih, menyembunyikan, dan menerapkan.
Kelebihan beban tidak dapat berbeda dengan nint dan System.IntPtr, dan nuint dan System.UIntPtr, saja.
Penimpaan dan implementasi dapat berbeda hanya dengan nint dan System.IntPtr, atau nuint dan System.UIntPtr.
Metode menyembunyikan metode lain yang hanya berbeda pada nint dan System.IntPtr, atau nuint dan System.UIntPtr.
Lain-lain
ekspresi nint dan nuint yang digunakan sebagai indeks array dipancarkan tanpa konversi.
static object GetItem(object[] array, nint index)
{
return array[index]; // ok
}
nint dan nuint tidak dapat digunakan sebagai jenis dasar enum dari C#.
enum E : nint // error: byte, sbyte, short, ushort, int, uint, long, or ulong expected
{
}
Pembacaan dan penulisan bersifat atomik untuk nint dan nuint.
Bidang dapat ditandai volatile untuk jenis nint dan nuint.
ECMA-334 15.5.4 tidak menyertakan enum dengan jenis dasar System.IntPtr atau System.UIntPtr.
default(nint) dan new nint() setara dengan (nint)0; default(nuint) dan new nuint() setara dengan (nuint)0.
typeof(nint) adalah typeof(IntPtr); typeof(nuint) adalah typeof(UIntPtr).
sizeof(nint) dan sizeof(nuint) didukung tetapi memerlukan kompilasi dalam konteks yang tidak aman (sebagaimana diperlukan untuk sizeof(IntPtr) dan sizeof(UIntPtr)).
Nilai bukan konstanta waktu kompilasi.
sizeof(nint) diimplementasikan sebagai sizeof(IntPtr) daripada IntPtr.Size; sizeof(nuint) diimplementasikan sebagai sizeof(UIntPtr) daripada UIntPtr.Size.
Diagnostik pengkompilasi untuk referensi tipe yang melibatkan nint atau nuint melaporkan nint atau nuint daripada IntPtr atau UIntPtr.
Metadata
nint dan nuint diwakili dalam metadata sebagai System.IntPtr dan System.UIntPtr.
Referensi tipe yang mencakup nint atau nuint dikeluarkan dengan System.Runtime.CompilerServices.NativeIntegerAttribute untuk menunjukkan bagian mana dari referensi tipe yang merupakan integer asli.
namespace System.Runtime.CompilerServices
{
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Event |
AttributeTargets.Field |
AttributeTargets.GenericParameter |
AttributeTargets.Parameter |
AttributeTargets.Property |
AttributeTargets.ReturnValue,
AllowMultiple = false,
Inherited = false)]
public sealed class NativeIntegerAttribute : Attribute
{
public NativeIntegerAttribute()
{
TransformFlags = new[] { true };
}
public NativeIntegerAttribute(bool[] flags)
{
TransformFlags = flags;
}
public readonly bool[] TransformFlags;
}
}
Pengodean referensi jenis dengan NativeIntegerAttribute tercakup dalam NativeIntegerAttribute.md.
Alternatif
Alternatif untuk pendekatan "jenis penghapusan" di atas adalah memperkenalkan jenis baru: System.NativeInt dan System.NativeUInt.
public readonly struct NativeInt
{
public IntPtr Value;
}
Tipe berbeda akan memungkinkan kelebihan beban yang berbeda dari IntPtr dan memungkinkan penguraian yang berbeda serta ToString().
Tetapi akan ada lebih banyak pekerjaan bagi CLR untuk menangani jenis ini secara efisien yang mengalahkan tujuan utama fitur - efisiensi.
Dan interoperabilitas dengan kode int asli yang ada yang menggunakan IntPtr akan lebih sulit.
Alternatif lain adalah menambahkan lebih banyak dukungan int asli untuk IntPtr dalam kerangka kerja tetapi tanpa dukungan kompilator tertentu.
Setiap konversi baru dan operasi aritmatika akan didukung oleh pengkompilasi secara otomatis.
Tetapi bahasa tidak akan menyediakan kata kunci, konstanta, atau operasi checked.
Rapat desain
- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-05-26.md
- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-06-13.md
- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-07-05.md#native-int-and-intptr-operators
- https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-10-23.md
- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-03-25.md
C# feature specifications