Aracılığıyla paylaş


Yerel boyutlu tamsayılar

Not

Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.

Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar, ilgili dil tasarım toplantısı (LDM) notlarındakayıt altına alınmıştır.

Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek içinbelirtimleri makalesinde bulabilirsiniz.

Özet

Yerel boyutlu imzalı ve imzasız tamsayı türleri için dil desteği.

Motivasyon birlikte çalışma senaryoları ve düşük düzeyli kitaplıklar içindir.

Tasarım

nint ve nuint tanımlayıcıları, yerel imzalı ve imzasız tamsayı türlerini temsil eden yeni bağlamsal anahtar sözcüklerdir. Tanımlayıcılar yalnızca ad araması bu program konumunda uygun bir sonuç bulamadıklarında anahtar sözcük olarak değerlendirilir.

nint x = 3;
_ = nint.Equals(x, 3);

nint ve nuint türleri, derleyicinin bu türler için ek dönüştürmeler ve işlemler sağlayarak onları yerel tamsayılar olarak ön plana çıkardığı System.IntPtr ve System.UIntPtr temel türleri tarafından temsil edilir.

Sabit

Sabit ifadeler nint veya nuinttüründe olabilir. Yerel int değişmez değerleri için doğrudan söz dizimi yoktur. Bunun yerine diğer tamsayı sabit değerlerinin örtük veya açık atamaları kullanılabilir: const nint i = (nint)42;.

nint sabitleri [ int.MinValue, int.MaxValue ] aralığındadır.

nuint sabitleri [ uint.MinValue, uint.MaxValue ] aralığındadır.

nint veya nuintMinValue veya MaxValue alanı yoktur çünkü nuint.MinValuedışında bu değerler sabit olarak yayılamaz.

Sabit katlama, tüm tekli işleçler { +, -, ~ } ve ikili işleçler { +, -, *, /, %, ==, !=, <, <=, >, >=, &, |, ^, <<, >> } için desteklenir. Sabit katlama işlemleri, derleyici platformundan bağımsız olarak tutarlı davranış sağlamak amacıyla yerel int türleri yerine Int32 ve UInt32 işlenenleri kullanılarak değerlendirilir. İşlem 32 bit sabit değerle sonuçlanırsa, derleme zamanında sabit katlama gerçekleştirilir. Aksi takdirde işlem çalışma zamanında yürütülür ve sabit olarak kabul edilmez.

Dönüşüm

nint ile IntPtrarasında ve nuint ile UIntPtrarasında bir kimlik dönüştürmesi vardır. Yerel tamsayılar ve yalnızca temel alınan türlere göre farklılık gösteren bileşik türler arasında bir kimlik dönüşümü vardır: diziler, Nullable<>, oluşturulan türler ve demetler.

Aşağıdaki tablolar özel türler arasındaki dönüştürmeleri kapsar. (Her dönüştürme için IL, farklıysa unchecked ve checked bağlamları için varyantları içerir.)

Aşağıdaki tabloda genel notlar:

  • conv.u, yerel tamsayıya sıfır uzatmalı bir dönüşümdür ve conv.i, yerel tamsayıya işaret uzatmalı bir dönüşümdür.
  • Hem genişletme hem de daraltma için checked bağlamları şunlardır:
    • signed to * için conv.ovf.*
    • unsigned to * için conv.ovf.*.un
  • genişletme için unchecked bağlamlar şunlardır:
    • signed to * için conv.i* (burada * hedef genişliktir)
    • unsigned to * için conv.u* (burada * hedef genişliktir)
  • daraltma için unchecked bağlamlar şunlardır:
    • any to signed * için conv.i* (burada * hedef genişliktir)
    • any to unsigned * için conv.u* (burada * hedef genişliktir)

Birkaç örnek alınıyor:

  • sbyte to nint ve sbyte to nuintconv.i kullanırken, byte to nint ve byte to nuintconv.u kullanıyor çünkü bunların hepsi genişletme.
  • nint to byte ve nuint to byteconv.u1 kullanırken nint to sbyte ve nuint to sbyteconv.i1kullanır. byte, sbyte, shortve ushort için "yığın türü" int32. Bu nedenle conv.i1 etkin bir şekilde "imzalı bir bayta indirilir ve ardından int32'ye kadar imzalanır", conv.u1 ise etkin bir şekilde "imzasız bir bayta indirilir ve sonra da sıfırdan int32'ye genişletilir".
  • checked void* to nint, conv.ovf.i.un'i, checked void* to long'nin conv.ovf.i8.un'ü kullandığı şekilde kullanır.
Işlenen Hedef Dönüşüm Illinois
object nint Kutudan çıkarma unbox
void* nint PointerToVoid nop / conv.ovf.i.un
sbyte nint Gizli Sayısal conv.i
byte nint Örtük Sayısal conv.u
short nint Örtük Sayısal conv.i
ushort nint Dolaylı Sayısal conv.u
int nint Örtük Numerik conv.i
uint nint Açık Sayısal conv.u / conv.ovf.i.un
long nint Açıkça Belirtilmiş Sayısal conv.i / conv.ovf.i
ulong nint Açık Sayısal conv.i / conv.ovf.i.un
char nint Gizli Sayısal conv.u
float nint Açık Sayısal conv.i / conv.ovf.i
double nint Açık Sayısal conv.i / conv.ovf.i
decimal nint Açıkça Belirtilmiş Sayısal long decimal.op_Explicit(decimal) conv.i / ... conv.ovf.i
IntPtr nint Kimlik
UIntPtr nint Hiç kimse
object nuint Kutu Açma unbox
void* nuint PointerToVoid Nop
sbyte nuint Açık Sayısal conv.i / conv.ovf.u
byte nuint Örtük Sayısal Değer conv.u
short nuint Açık Sayısal conv.i / conv.ovf.u
ushort nuint Gizli Sayısal conv.u
int nuint Açık Sayısal Değer conv.i / conv.ovf.u
uint nuint Gizli Sayısal conv.u
long nuint Açık Sayısal conv.u / conv.ovf.u
ulong nuint Açık Sayısal Değer conv.u / conv.ovf.u.un
char nuint Örtük Sayısal conv.u
float nuint Açıkça Belirtilmiş Sayısal conv.u / conv.ovf.u
double nuint Açık Sayısal conv.u / conv.ovf.u
decimal nuint Açık Sayısal ulong decimal.op_Explicit(decimal) conv.u / ... conv.ovf.u.un
IntPtr nuint Hiç kimse
UIntPtr nuint Kimlik
Sayım nint Açık Belirtim
Numaralandırma nuint Açık Sayım
İşleç Hedef Dönüşüm Illinois
nint object Boks box
nint void* Boş İşaretçi nop / conv.ovf.u
nint nuint Açık Sayısal Veri conv.u (atlanabilir) / conv.ovf.u
nint sbyte Açıkça Tanımlanmış Sayısal conv.i1 / conv.ovf.i1
nint byte Açık Sayısal İfade conv.u1 / conv.ovf.u1
nint short Açık Sayısal conv.i2 / conv.ovf.i2
nint ushort Açık Sayısal conv.u2 / conv.ovf.u2
nint int Açık Sayısal conv.i4 / conv.ovf.i4
nint uint Açık Sayısal conv.u4 / conv.ovf.u4
nint long Örtük Sayısal Değer conv.i8
nint ulong Açık Sayısal conv.i8 / conv.ovf.u8
nint char Açık Sayısal conv.u2 / conv.ovf.u2
nint float Gizli Sayısal conv.r4
nint double Örtük Numerik conv.r8
nint decimal Örtük Sayısal conv.i8 decimal decimal.op_Implicit(long)
nint IntPtr Kimlik
nint UIntPtr Hiç kimse
nint Sayım Açık Sayım
nuint object Boks box
nuint void* Boş İşaretçi Nop
nuint nint Açık Sayısal conv.i(atlanabilir) / conv.ovf.i.un
nuint sbyte Açıkça Belirtilmiş Sayısal conv.i1 / conv.ovf.i1.un
nuint byte Explicit Numeric conv.u1 / conv.ovf.u1.un
nuint short Açıkça Tanımlanmış Sayısal conv.i2 / conv.ovf.i2.un
nuint ushort Açık Sayısal conv.u2 / conv.ovf.u2.un
nuint int Açık Sayısal conv.i4 / conv.ovf.i4.un
nuint uint Açıkça Belirtilmiş Sayısal conv.u4 / conv.ovf.u4.un
nuint long Açık Sayısal conv.u8 / conv.ovf.i8.un
nuint ulong Örtük Sayısal conv.u8
nuint char Açıkça Tanımlı Sayısal conv.u2 / conv.ovf.u2.un
nuint float Örtük Sayısal conv.r.un conv.r4
nuint double Gizli Sayısal conv.r.un conv.r8
nuint decimal Örtük Sayısal conv.u8 decimal decimal.op_Implicit(ulong)
nuint IntPtr Hiç kimse
nuint UIntPtr Kimlik
nuint Numaralandırma Açıkça Belirtilen Sıralama

A'den Nullable<B> dönüştürme:

  • A'dan B'e bir kimlik dönüşümü veya örtük dönüşüm varsa, örtük null atanabilir dönüşüm;
  • A'den B'e açık bir dönüştürme varsa, açık bir boş değer atanabilir dönüştürme yapılabilir;
  • aksi takdirde geçersiz.

Nullable<A>'den B dönüştürme:

  • Kimlik veya örtük ya da açık sayısal dönüşüm varsa, A'den B'e açık null dönüşümü yapın;
  • aksi takdirde geçersiz.

Nullable<A>'den Nullable<B> dönüştürme:

  • A'den B'e bir kimlik dönüşümü varsa;
  • A'den B'ye örtük veya açık bir sayısal dönüşüm varsa, açık şekilde null atanabilir bir dönüştürme yapılabilir.
  • aksi takdirde geçersiz.

Işleç

Önceden tanımlanmış işleçler aşağıdaki gibidir. İşlenenlerden en az biri veya türündeyse, bu işleçler örtük dönüştürmeler için normal kurallara göre aşırı yükleme çözümlemesi sırasında dikkate alınır.

(Her işlecin IL'i, unchecked ve farklıysa checked bağlamları için varyantları içerir.)

Tekli İşleç İmzası Illinois
+ 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
İkili İşleç İmzası Illinois
+ 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

Bazı ikili işleçler için IL işleçleri ek işlenen türlerini destekler (bkz. ECMA-335 III.1.5 İşlenen türü tablosu). Ancak C# tarafından desteklenen operand türleri kümesi, basitlik ve dildeki mevcut operatörlerle tutarlılık açısından sınırlıdır.

Bağımsız değişkenlerin ve dönüş türlerinin nint? ve nuint?olduğu işleçlerin yükseltilmiş sürümleri desteklenir.

Bileşik atama işlemleri, x veya y yerel int'ler olduğu x op= y önceden tanımlanmış işleçlere sahip diğer temel türlerle aynı kuralları izler. Özellikle, ifade T'in x türünde olduğu ve x'ün yalnızca bir kez değerlendirildiği durumlarda x = (T)(x op y) olarak bağlanır.

Kaydırma işleçleri, sizeof(nint) 4 ise kaydırılacak bit sayısını 5 bit olarak, sizeof(nint) 8 ise 6 bit olarak maskelemelidir. (C# belirtiminde §12.11) bölümüne bakın).

C#9 derleyicisi, önceki bir dil sürümüyle derlenirken önceden tanımlanmış yerel tamsayı işleçlerine bağlama hatalarını bildirir, ancak yerel tamsayılara ve yerel tamsayılardan önceden tanımlanmış dönüştürmelerin kullanılmasına izin verir.

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
    }
}

İşaretçi aritmetiği

Yerel tamsayı uzaklıklarına sahip işaretçi ekleme veya çıkarma işlemleri için C# dilinde önceden tanımlanmış işleç yoktur. Bunun yerine, nint ve nuint değerleri long ve ulong olarak yükseltilir ve işaretçi aritmetiği bu türler için önceden tanımlanmış işleçler kullanır.

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)

İkili sayısal yükseltmeler

ikili sayısal yükseltmeleri bilgilendirici metin (bkz. C# belirtimindeki §12.4.7.3) aşağıdaki gibi güncelleştirilir:

  • Aksi takdirde, işlenenlerden biri ulongtüründeyse, diğer işlenen ulongtürüne dönüştürülür veya diğer işlenen sbyte, short, int, nintveya longtüründeyse bağlama zamanı hatası oluşur.
  • Aksi takdirde, işlenenlerden biri nuinttüründeyse, diğer işlenen nuinttürüne dönüştürülür veya diğer işlenen sbyte, short, int, nintveya longtüründeyse bağlama zamanı hatası oluşur.
  • Aksi halde, operantlardan biri longtüründeyse, diğer operant longtürüne dönüştürülür.
  • Aksi takdirde, işlenenlerden biri uint türündeyse ve diğer işlenen sbyte, short, nint, veya inttüründeyse, her iki işlenen de longtürüne dönüştürülür.
  • Aksi takdirde, işlenenlerden biri uinttüründeyse, diğer işlenen uinttürüne dönüştürülür.
  • Aksi takdirde, işlenenlerden biri ninttüründeyse, diğer işlenen ninttürüne dönüştürülür.
  • Aksi takdirde, her iki işlenen de inttürüne dönüştürülür.

Dinamik

Dönüştürmeler ve işleçler derleyici tarafından sentezlenir ve temel IntPtr ve UIntPtr türlerinin bir parçası değildir. Sonuç olarak bu dönüştürmeler ve işleçler dynamiciçin çalışma zamanı bağlayıcısından kullanılamaz .

nint x = 2;
nint y = x + x; // ok
dynamic d = x;
nint z = d + x; // RuntimeBinderException: '+' cannot be applied 'System.IntPtr' and 'System.IntPtr'

Tür üyeleri

nint veya nuint için tek oluşturucu parametresiz oluşturucudur.

Aşağıdaki System.IntPtr ve System.UIntPtrüyeleri,nint veya nuint'ten açıkça dışındadır:

// 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();

System.IntPtr ve System.UIntPtr'nin kalan üyeleri, nint ve nuint'e örtük olarak eklenir. .NET Framework 4.7.2 için:

public override bool Equals(object obj);
public override int GetHashCode();
public override string ToString();
public string ToString(string format);

System.IntPtr ve System.UIntPtrtarafından uygulanan arabirimler, nint ve nuintiçerisine örtülü olarak dahildir ve temel türlerin kullanımları karşılık gelen yerel tamsayı türleriyle değiştirilir. Örneğin, IntPtrISerializable, IEquatable<IntPtr>, IComparable<IntPtr>uygularsa nintISerializable, IEquatable<nint>, IComparable<nint>uygular.

Geçersiz kılma, saklama ve uygulama

nint ve System.IntPtrile nuint ve System.UIntPtrgeçersiz kılma, gizleme ve uygulama için eşdeğer kabul edilir.

Aşırı yüklemeler yalnızca nint ve System.IntPtrile nuint ve System.UIntPtrfarklılık gösteremez. Geçersiz kılmalar ve uygulamalar, yalnızca nint ve System.IntPtrveya nuint ve System.UIntPtrile sınırlı olarak farklılık gösterebilir. Yöntemler, yalnızca nint ve System.IntPtrveya nuint ve System.UIntPtrile farklılık gösteren diğer yöntemleri gizler.

Çeşitli

dizi dizinleri olarak kullanılan nint ve nuint ifadeleri dönüştürme olmadan yayılır.

static object GetItem(object[] array, nint index)
{
    return array[index]; // ok
}

nint ve nuint, C# dilinden enum temel türü olarak kullanılamaz.

enum E : nint // error: byte, sbyte, short, ushort, int, uint, long, or ulong expected
{
}

Okuma ve yazma işlemleri nint ve nuintiçin atomiktir.

Alanlar nint ve nuinttürleri için volatile olarak işaretlenebilir. ECMA-334 15.5.4, temel tür System.IntPtr veya System.UIntPtr olan enum içermez.

default(nint) ve new nint()(nint)0eşdeğerdir; default(nuint) ve new nuint()(nuint)0eşdeğerdir.

typeof(nint), typeof(IntPtr)'dir; typeof(nuint), typeof(UIntPtr)'tür.

sizeof(nint) ve sizeof(nuint) desteklenir, ancak güvenli olmayan bir bağlamda derleme gerektirir (sizeof(IntPtr) ve sizeof(UIntPtr)için gerektiği gibi). Değerler derleme zamanı sabitleri değildir. sizeof(nint) IntPtr.Sizeyerine sizeof(IntPtr) olarak uygulanır; sizeof(nuint)UIntPtr.Sizeyerine sizeof(UIntPtr) olarak uygulanır.

Tür başvurularını içeren derleyici tanılamaları, IntPtr veya UIntPtryerine nint veya nuint'e ilişkin olarak nint veya nuint'ü raporlar.

Meta veriler

nint ve nuint meta verilerde System.IntPtr ve System.UIntPtrolarak gösterilir.

nint veya nuint içeren tür başvuruları, tür başvurusunun hangi bölümlerinin yerel int olduğunu belirtmek için bir System.Runtime.CompilerServices.NativeIntegerAttribute ile birlikte gönderilir.

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;
    }
}

NativeIntegerAttribute ile tür başvurularının kodlaması NativeIntegerAttribute.mdkapsamındadır.

Alternatif

Yukarıdaki "tür silme" yaklaşımının bir alternatifi de yeni türleri tanıtmaktır: System.NativeInt ve System.NativeUInt.

public readonly struct NativeInt
{
    public IntPtr Value;
}

Ayrı türler, IntPtr'dan farklı olarak aşırı yüklemeye izin verir ve ayrıca ayrıştırmayı ToString()'den farklı hale getirebilir. Ancak CLR'nin bu türleri verimli bir şekilde işlemesi için daha fazla çalışma olacaktır ve bu da özelliğin birincil amacı olan verimliliği yener. Ayrıca IntPtr kullanan mevcut yerel int koduyla birlikte çalışmak daha zor olacaktır.

Başka bir alternatif, çerçevedeki IntPtr için daha yerel int desteği eklemektir ancak belirli bir derleyici desteği olmadan. Tüm yeni dönüştürmeler ve aritmetik işlemler derleyici tarafından otomatik olarak desteklenir. Ancak dil anahtar sözcükler, sabitler veya checked işlemleri sağlamaz.

Tasarım toplantıları