Aracılığıyla paylaş


8 Çeşit

8.1 Genel

C# dilinin türleri iki ana kategoriye ayrılır: başvuru türleri ve değer türleri. Hem değer türleri hem de başvuru türleri, bir veya daha fazla tür parametresi alan genel türler olabilir. Tür parametreleri hem değer türlerini hem de başvuru türlerini belirleyebilir.

type
    : reference_type
    | value_type
    | type_parameter
    | pointer_type     // unsafe code support
    ;

pointer_type (§23.3) yalnızca güvenli olmayan kodda (§23) kullanılabilir.

Değer türleri, değer türlerinin değişkenlerinin verilerini doğrudan içermesi nedeniyle başvuru türlerinden farklılık gösterirken, başvuru türlerinin değişkenleri kendi verilerine başvuru depolar ve ikincisi nesne olarak bilinir. Başvuru türleriyle, iki değişkenin aynı nesneye başvurması ve bu nedenle bir değişkendeki işlemlerin diğer değişken tarafından başvuruda bulunan nesneyi etkilemesi mümkündür. Değer türleriyle, değişkenlerin her biri kendi veri kopyasına sahiptir ve biri üzerindeki işlemlerin diğerini etkilemesi mümkün değildir.

Not: Bir değişken bir başvuru veya çıkış parametresi olduğunda, kendi depolama alanı yoktur, ancak başka bir değişkenin depolamasına başvurur. Bu durumda ref veya out değişkeni, farklı bir değişken için değil, başka bir değişken için etkili bir diğer addır. dipnot

C#'nin tür sistemi, herhangi bir türde bir değerin nesne olarak ele alınabilmesi için birleştirilir. C# içindeki her tür doğrudan veya dolaylı olarak sınıf türünden object türetilir ve object tüm türlerin nihai temel sınıfıdır. Başvuru türlerinin değerleri, sadece tür object olarak görüntülendiklerinde nesne olarak değerlendirilir. Değer türlerinin değerleri, kutulama ve kutu açma işlemleri (§8.3.13) gerçekleştirilerek nesne olarak değerlendirilir.

Kolaylık sağlamak için, bu belirtim boyunca, bazı kitaplık türü adları tam ad nitelikleri kullanılmadan yazılır. Daha fazla bilgi için §C.5 adresine bakın.

8.2 Başvuru türleri

8.2.1 Genel

Başvuru türü bir sınıf türü, arabirim türü, dizi türü, temsilci türü veya dynamic türüdür. Boş değer atanamayan her başvuru türü için, türün adına eklenerek ? belirtilen karşılık gelen bir null atanabilir başvuru türü vardır.

reference_type
    : non_nullable_reference_type
    | nullable_reference_type
    ;

non_nullable_reference_type
    : class_type
    | interface_type
    | array_type
    | delegate_type
    | 'dynamic'
    ;

class_type
    : type_name
    | 'object'
    | 'string'
    ;

interface_type
    : type_name
    ;

array_type
    : non_array_type rank_specifier+
    ;

non_array_type
    : value_type
    | class_type
    | interface_type
    | delegate_type
    | 'dynamic'
    | type_parameter
    | pointer_type      // unsafe code support
    ;

rank_specifier
    : '[' ','* ']'
    ;

delegate_type
    : type_name
    ;

nullable_reference_type
    : non_nullable_reference_type nullable_type_annotation
    ;

nullable_type_annotation
    : '?'
    ;

pointer_type yalnızca güvenli olmayan kodda (§23.3) kullanılabilir. nullable_reference_type daha ayrıntılı olarak §8.9'da tartışılır.

Referans türü değeri, türün bir örneğine bir referanstır ve bu da bir nesne olarak bilinir. Özel değer null tüm başvuru türleriyle uyumludur ve bir örneğin yokluğunu gösterir.

8.2.2 Sınıf türleri

Sınıf türü , veri üyeleri (sabitler ve alanlar), işlev üyeleri (yöntemler, özellikler, olaylar, dizin oluşturucular, işleçler, örnek oluşturucuları, sonlandırıcılar ve statik oluşturucular) ve iç içe türler içeren bir veri yapısı tanımlar. Sınıf türleri, türetilmiş sınıfların temel sınıfları genişletebildiği ve uzmanlaşabileceği bir mekanizma olan devralmayı destekler. Sınıf türlerinin örnekleri object_creation_expression(§12.8.17.2) kullanılarak oluşturulur.

Sınıf türleri §15'te açıklanmıştır.

Bazı önceden tanımlanmış sınıf türleri, aşağıdaki tabloda açıklandığı gibi C# dilinde özel bir anlama sahiptir.

Sınıf türü Açıklama
System.Object Diğer tüm türlerin nihai temel sınıfı. Bkz . §8.2.3.
System.String C# dilinin dize türü. Bkz . §8.2.5.
System.ValueType Tüm değer türlerinin temel sınıfı. Bkz . §8.3.2.
System.Enum Tüm enum türlerin temel sınıfı. Bkz . §19.5.
System.Array Tüm dizi türlerinin temel sınıfı. Bkz . §17.2.2.
System.Delegate Tüm delegate türlerin temel sınıfı. Bkz . §20.1.
System.Exception Tüm özel durum türlerinin temel sınıfı. Bkz . §21.3.

8.2.3 Nesne türü

object Sınıf türü, diğer tüm türlerin nihai temel sınıfıdır. C# içindeki her tür doğrudan veya dolaylı olarak sınıf türünden object türetilir.

anahtar sözcüğü object , önceden tanımlanmış sınıfı System.Objectiçin bir diğer addır.

8.2.4 Dinamik tür

dynamic türü, object gibi, herhangi bir nesneye başvurabilir. türündeki dynamicifadelere işlemler uygulandığında, program çalıştırana kadar çözümlemeleri ertelenecek. Bu nedenle, işlem başvurulan nesneye yasal olarak uygulanamazsa, derleme sırasında hata verilmez. Bunun yerine, çalışma zamanında işlemin çözümü başarısız olduğunda bir özel durum oluşturulur.

Türü dynamicdaha ayrıntılı olarak §8.7 ve dinamik bağlama ise §12.3.1'de açıklanmıştır.

8.2.5 Dize türü

string türü, doğrudan object sınıfından devralınan mühürlü bir sınıf türüdür. sınıfının örnekleri string Unicode karakter dizelerini temsil eder.

Türün string değerleri dize sabitleri (§6.4.5.6) olarak yazılabilir.

anahtar sözcüğü string , önceden tanımlanmış sınıfı System.Stringiçin bir diğer addır.

8.2.6 Arabirim türleri

Arabirim bir sözleşme tanımlar. Arabirim uygulayan bir sınıf veya yapı, sözleşmesine uymalıdır. Bir arabirim birden çok temel arabirimden devralabilir ve bir sınıf veya yapı birden çok arabirim uygulayabilir.

Arabirim türleri §18'de açıklanmıştır.

8.2.7 Dizi türleri

Dizi, hesaplanan dizinler aracılığıyla erişilen sıfır veya daha fazla değişken içeren bir veri yapısıdır. Dizinin öğeleri olarak da adlandırılan bir dizideki değişkenlerin tümü aynı türdedir ve bu tür dizinin öğe türü olarak adlandırılır.

Dizi türleri §17'de açıklanmıştır.

8.2.8 Temsilci türleri

Bir delege, bir veya daha fazla yönteme başvuran bir veri yapısıdır. Örneğin yöntemler, bunlara karşılık gelen nesne örneklerine de başvurur.

Not: C veya C++ içindeki bir temsilcinin en yakın eşdeğeri bir işlev işaretçisidir, ancak işlev işaretçisi yalnızca statik işlevlere başvurabilirken, temsilci hem statik hem de örnek yöntemlerine başvurabilir. İkinci durumda, temsilci yalnızca yöntemin giriş noktasına başvuru depolamakla kalmaz, aynı zamanda yöntemin çağrılacağı nesne örneğine de başvuru depolar. dipnot

Temsilci türleri §20'de açıklanmıştır.

8.3 Değer türleri

8.3.1 Genel

Değer türü bir yapı türü veya numaralandırma türüdür. C# basit türler olarak adlandırılan önceden tanımlanmış yapı türleri kümesi sağlar. Basit türler anahtar sözcüklerle tanımlanır.

value_type
    : non_nullable_value_type
    | nullable_value_type
    ;

non_nullable_value_type
    : struct_type
    | enum_type
    ;

struct_type
    : type_name
    | simple_type
    | tuple_type
    ;

simple_type
    : numeric_type
    | 'bool'
    ;

numeric_type
    : integral_type
    | floating_point_type
    | 'decimal'
    ;

integral_type
    : 'sbyte'
    | 'byte'
    | 'short'
    | 'ushort'
    | 'int'
    | 'uint'
    | 'long'
    | 'ulong'
    | 'char'
    ;

floating_point_type
    : 'float'
    | 'double'
    ;

tuple_type
    : '(' tuple_type_element (',' tuple_type_element)+ ')'
    ;
    
tuple_type_element
    : type identifier?
    ;
    
enum_type
    : type_name
    ;

nullable_value_type
    : non_nullable_value_type nullable_type_annotation
    ;

Başvuru türü değişkenlerine kıyasla, değer türündeki bir değişken, yalnızca değer türü null atanabilir ise null içerebilir (§8.3.12). Null değer atanamayan her değer türü için, aynı değer kümesinin yanı sıra değerini belirten karşılık gelen bir null atanabilir değer nulltürü vardır.

Değer türündeki bir değişkene atama, atanmakta olan değerin bir kopyasını oluşturur. Bu, başvuru türündeki bir değişkene atamadan farklıdır; çünkü burada başvuru kopyalanır, ancak başvuru tarafından tanımlanan nesne kopyalanmaz.

8.3.2 System.ValueType türü

Tüm değer türleri, örtük olarak classSystem.ValueType sınıfından devralır ve bu da sınıf object'den devralınır. Herhangi bir türün bir değer türünden türetmesi mümkün değildir ve bu nedenle değer türleri örtük olarak mühürlenir (§15.2.2.3).

System.ValueType Bunun kendisi bir value_type olmadığını unutmayın. Tüm value_type değerlerinin otomatik olarak türetildiği bir class_typetir.

8.3.3 Varsayılan oluşturucular

Tüm değer türleri, varsayılan oluşturucu olarak adlandırılan bir genel parametresiz örnek oluşturucuyu örtük olarak bildirir. Varsayılan oluşturucu, değer türü için varsayılan değer olarak bilinen sıfırdan başlatılan bir örnek döndürür:

  • Tüm simple_typeiçin varsayılan değer, tüm sıfırların bit deseni tarafından üretilen değerdir:
    • sbyte, , byte, short, ushort, int, uint, longve ulongiçin varsayılan değerdir0.
    • için charvarsayılan değer şeklindedir '\x0000'.
    • için floatvarsayılan değer şeklindedir 0.0f.
    • için doublevarsayılan değer şeklindedir 0.0d.
    • için decimalvarsayılan değerdir 0m (yani, 0 ölçeğindeki sıfır değeridir).
    • için boolvarsayılan değer şeklindedir false.
    • enum_typeE için varsayılan değer 0 olup E türüne dönüştürülür.
  • bir struct_type için varsayılan değer, tüm değer türü alanlarını varsayılan değerlerine ve tüm başvuru türü alanlarını nulldeğerine ayarlayarak üretilen değerdir.
  • bir nullable_value_type için varsayılan değer, özelliğinin HasValue false olduğu bir örnektir. Varsayılan değer, null atanabilir değer türünün null değeri olarak da bilinir. Böyle bir değerin Value özelliğinin okunmaya çalışılması, tür System.InvalidOperationException özeldurumunun atılmasına (§8.3.12) neden olur.

Diğer tüm örnek oluşturucular gibi, bir değer türünün varsayılan oluşturucusu new işleci kullanılarak çağrılır.

Not: Verimlilik nedenleriyle, bu gereksinim aslında uygulamanın bir oluşturucu çağrısı oluşturmasını sağlamak için tasarlanmamıştır. Değer türleri için, varsayılan değer ifadesi (§12.8.21) varsayılan oluşturucuyu kullanarak aynı sonucu verir. dipnot

Örnek: Aşağıdaki kodda, i ve j değişkenleri ksıfır olarak başlatılır.

class A
{
    void F()
    {
        int i = 0;
        int j = new int();
        int k = default(int);
    }
}

son örnek

Her değer türünün örtük olarak bir ortak parametresiz örnek oluşturucusunun olması nedeniyle, yapı türünün parametresiz oluşturucunun açık bir bildirimini içermesi mümkün değildir. Ancak yapı türünün parametreli örnek oluşturucuları (§16.4.9) bildirmesine izin verilir.

8.3.4 Yapı türleri

Yapı türü, sabitleri, alanları, yöntemleri, özellikleri, olayları, dizin oluşturucuları, işleçleri, örnek oluşturucularını, statik oluşturucuları ve iç içe yerleştirilmiş türleri bildirebilen bir değer türüdür. Yapı türlerinin bildirimi §16'da açıklanmıştır.

8.3.5 Basit türler

C# basit türler olarak adlandırılan önceden tanımlanmış struct türleri kümesi sağlar. Basit türler anahtar sözcükler aracılığıyla tanımlanır, ancak bu anahtar sözcükler yalnızca aşağıdaki tabloda açıklandığı gibi struct ad alanında önceden tanımlanmış System türleri için diğer adlardır.

Anahtar Sözcük Adlandırılmış tür
sbyte System.SByte
byte System.Byte
short System.Int16
ushort System.UInt16
int System.Int32
uint System.UInt32
long System.Int64
ulong System.UInt64
char System.Char
float System.Single
double System.Double
bool System.Boolean
decimal System.Decimal

Bir basit tür bir yapı türüne diğer ad verdiğinden, her basit türün üyeleri bulunur.

Örnek: int içinde bildirilen System.Int32 üyeleri ve System.Object'den devralınan üyeleri içerir ve aşağıdaki deyimlere izin verilir:

int i = int.MaxValue;      // System.Int32.MaxValue constant
string s = i.ToString();   // System.Int32.ToString() instance method
string t = 123.ToString(); // System.Int32.ToString() instance method

son örnek

Not: Basit türler, bazı ek işlemlere izin verdikleri için içindeki diğer yapı türlerinden farklıdır:

  • Çoğu basit tür, değerlerin literal olarak (§6.4.5) yazılarak oluşturulmasına izin verir, ancak C# genel olarak struct türlerinin literal değerleri için bir sağlamlık sağlamaz. Örnek: 123 bir int türünün değişmez değeridir ve 'a' bir char türünün değişmez değeridir. son örnek
  • bir ifadenin işlenenlerinin tümü basit tür sabitleri olduğunda, derleyicinin derleme zamanında ifadeyi değerlendirmesi mümkündür. Böyle bir ifade constant_expression (§12.23) olarak bilinir. Diğer yapı türleri tarafından tanımlanan işleçleri içeren ifadeler sabit ifadeler olarak kabul edilmez
  • Bildirimler aracılığıyla const , basit türlerin sabitlerini bildirmek mümkündür (§15.4). Diğer yapı türlerinin sabitlerine sahip olmak mümkün değildir, ancak benzer bir etki statik salt okunur alanlar tarafından sağlanır.
  • Basit türleri içeren dönüştürmeler, diğer yapı türleri tarafından tanımlanan dönüştürme işleçlerinin değerlendirilmesine katılabilir, ancak kullanıcı tanımlı dönüştürme işleci hiçbir zaman başka bir kullanıcı tanımlı dönüştürme işlecinin (§10.5.3) değerlendirmesine katılamıyor.

bitiş notunu seçin.

8.3.6 Integral türleri

C# dokuz tam sayı türünü destekler: sbyte, byte, short, ushort, int, , uint, longulongve char. İntegral türleri aşağıdaki değer boyutlarına ve aralıklarına sahiptir:

  • sbyte türü, -128'den 127'ye kadar olan değerleri (dahil) kapsayan imzalı 8 bitlik tamsayıları temsil eder.
  • türü, byte 'den 0255değerine (dahil) kadar olan işaretsiz 8 bitlik tamsayıları temsil eder.
  • short türü, -32768 ile 32767 değerleri arasında (dahil) imzalı 16 bit tamsayıları temsil eder.
  • türü, ushort 'den 065535değerine (dahil) kadar olan işaretsiz 16 bit tamsayıları temsil eder.
  • int türü, -2147483648 ile 2147483647 (dahil) arasında değerlere sahip imzalı 32 bit tamsayıları temsil eder.
  • uint türü, 0 'den 4294967295 değerine kadar olan (dahil) işaretsiz 32-bit tamsayıları temsil eder.
  • long türü, -9223372036854775808 ile 9223372036854775807 aralığındaki, kapsayan, imzalı 64 bit tamsayıları temsil eder.
  • ulong türü, 0 ile 18446744073709551615 arasındaki değerler dahil olmak üzere işaretsiz 64 bit tamsayıları temsil eder.
  • türü, char 'den 065535değerine (dahil) kadar olan işaretsiz 16 bit tamsayıları temsil eder. Türü için olası değerler char kümesi Unicode karakter kümesine karşılık gelir.

    Not: char ile aynı gösterime sahip olmasına rağmen, bir tür üzerinde izin verilen tüm işlemler diğerinde izin verilmez. dipnot

tüm imzalı integral türleri, ikinin tamamlayıcı biçimi kullanılarak temsil edilir.

birli ve ikili integral_type işleçleri her zaman §12.4.7'de ayrıntılı olarak açıklandığı gibi imzalı 32 bit duyarlık, imzasız 32 bit duyarlık, imzalı 64 bit duyarlık veya işaretsiz 64 bit duyarlık ile çalışır.

Türü char bir integral türü olarak sınıflandırılır, ancak iki şekilde diğer integral türlerinden farklıdır:

  • Diğer türlerden char türüne önceden tanımlanmış örtük dönüşümler yoktur. Özellikle, byte ve ushort türleri char türünü kullanarak tamamen temsil edilebilir değer aralıklarına sahip olsa da, sbayt, bayt veya ushort türlerinden char türüne örtük dönüşümler mevcut değildir.
  • Türün char sabitleri, karakter türüne dönüştürme ile birlikte character_literals veya integer_literal olarak yazılmalıdır.

Örnek: (char)10 ile '\x000A'aynıdır. son örnek

checked ve unchecked işleçleri ve deyimleri, tamsayı türü aritmetik işlemler ve dönüştürmeler (§12.8.20) için taşma denetimini denetlemek için kullanılır. Bir checked bağlamda, taşma bir derleme zamanı hatası meydana getirir veya bir System.OverflowException oluşturulmasına yol açar. Bağlamda unchecked taşmalar yoksayılır ve hedef türe sığmayan üst sıradaki bitler atılır.

8.3.7 Kayan nokta türleri

C# iki kayan nokta türünü destekler: float ve double. float ve double türleri, aşağıdaki değer kümelerini sağlayan 32 bit tek duyarlıklı ve 64 bit çift duyarlıklı IEC 60559 biçimleri kullanılarak temsil edilir:

  • Pozitif sıfır ve negatif sıfır. Çoğu durumda pozitif sıfır ve negatif sıfır, basit sıfır değeriyle aynı şekilde davranır, ancak bazı işlemler ikisi arasında ayrım (§12.10.3) gerçekleştirir.
  • Pozitif sonsuzluk ve negatif sonsuzluk. Sonsuzlar, sıfır olmayan bir sayıyı sıfıra bölme gibi işlemler tarafından üretilir.

    Örnek: 1.0 / 0.0 pozitif sonsuzluk verir ve –1.0 / 0.0 negatif sonsuzluk verir. son örnek

  • Sayı Olmayan değeri, genellikle NaN olarak kısaltılır. NaN'ler, sıfırı sıfıra bölme gibi geçersiz kayan nokta işlemleriyle oluşturulur.
  • Formun sıfır olmayan değerlerin sonlu kümesi × m × 2e, burada s 1 veya −1, m ve e ise belirli kayan nokta türüne göre belirlenir: içinfloat, 0 <m< 2²⁴ ve −149 ≤ e ≤ 104 ve içindouble, 0 <m< 2⁵³ ve −1075 ≤ e ≤ 970. Normalleştirilmiş kayan noktalı sayılar geçerli sıfır olmayan değerler olarak kabul edilir. C# uyumlu bir uygulamanın normalleştirilmiş kayan nokta sayılarını desteklemesini gerektirmez veya yasaklamaz.

Bu float tür, yaklaşık 1,5 × 10⁻⁴⁵ ile 3,4 × 10³⁸ arasındaki değerleri 7 basamaklı duyarlıkla temsil edebilir.

Bu double tür, yaklaşık 5,0 × 10⁻³²⁴ ile 1,7 × 10³⁰⁸ arasında 15-16 basamaklı bir duyarlıkla değerleri temsil edebilir.

İkili işlecin işlenenlerinden biri kayan nokta türündeyse, §12.4.7'de ayrıntılı olarak açıklandığı gibi standart sayısal yükseltmeler uygulanır ve işlem veya float duyarlıkla double gerçekleştirilir.

Atama işleçleri de dahil olmak üzere kayan nokta işleçleri hiçbir zaman özel durum oluşturmaz. Bunun yerine, olağanüstü durumlarda kayan nokta işlemleri aşağıda açıklandığı gibi sıfır, sonsuz veya NaN üretir:

  • Kayan nokta işleminin sonucu, hedef biçimde en yakın temsil edilebilir değere yuvarlanir.
  • Kayan nokta işleminin sonucunun büyüklüğü hedef biçim için çok küçükse, işlemin sonucu pozitif sıfır veya negatif sıfır olur.
  • Kayan nokta işleminin sonucunun büyüklüğü hedef biçim için çok büyükse, işlemin sonucu pozitif sonsuz veya negatif sonsuz olur.
  • Kayan nokta işlemi geçersizse, işlemin sonucu NaN olur.
  • Kayan nokta işleminin işlenenlerinden biri veya her ikisi de NaN ise, işlemin sonucu NaN olur.

Kayan nokta işlemleri, işlemin sonuç türünden daha yüksek hassasiyetle gerçekleştirilebilir. Kayan nokta türündeki bir değeri türünün tam duyarlığıyla zorlamak için açık bir atama (§12.9.7) kullanılabilir.

Örnek: Bazı donanım mimarileri, türünden daha büyük aralık ve duyarlık ile "genişletilmiş" veya "uzun çift" kayan double nokta türünü destekler ve bu daha yüksek duyarlık türünü kullanarak tüm kayan nokta işlemlerini örtük olarak gerçekleştirir. Yalnızca performans açısından aşırı maliyetle bu tür donanım mimarileri daha az duyarlıkla kayan nokta işlemleri gerçekleştirmek için yapılabilir ve hem performans hem de duyarlık kaybı için bir uygulama gerektirmek yerine, C# tüm kayan nokta işlemleri için daha yüksek bir duyarlık türü kullanılmasına izin verir. Daha kesin sonuçlar sunmanın dışında, bu nadiren ölçülebilir etkilere sahiptir. Ancak, çarpımın aralığın dışında x * y / z bir sonuç ürettiği, ancak sonraki bölmenin geçici sonucu aralığa geri double getirdiği form doubleifadelerinde, ifadenin daha yüksek aralık biçiminde değerlendirildiği gerçeği sonsuzluk yerine sonlu bir sonucun üretilmesine neden olabilir. son örnek

8.3.8 Ondalık türü

Tür decimal , finansal ve parasal hesaplamalar için uygun olan 128 bitlik bir veri türüdür. Tür, decimal en az -7,9 × 10⁻²⁸ ile 7,9 × 10²⁸ aralığındaki değerleri en az 28 basamaklı duyarlıkla temsil edebilir.

Türün decimal sonlu değer kümesi, (–1)v × c × 10⁻e biçimindedir, burada v işareti 0 veya 1, katsayı c 0 ≤ c<Cmax tarafından verilir ve ölçek e , EmineEmax şeklindedir; burada Cmax en az 1 × 10²⁸, Emin ≤ 0, ve Emax ≥ 28. Türün decimal imzalı sıfırları, sonsuzlukları veya NaN değerlerini desteklemesi gerekmez.

Bir decimal, 10'un bir kuvvetiyle ölçeklendirilmiş bir tamsayı olarak temsil edilir. decimaldeğerinden küçük 1.0mmutlak değere sahip s için, değer en az 28. ondalık basamayı tam olarak gösterir. Mutlak değeri decimaldan büyük veya eşit olan 1.0mler için, değer en az 28 basamak hassasiyetle doğrudur. float ve double veri türlerinin aksine, 0.1 gibi ondalık kesirli sayılar tam olarak ondalık gösterimde temsil edilebilir. float ve double gösterimlerinde, bu tür sayılar genellikle sonlandırıcı olmayan ikili genişletmelere sahiptir ve bu da bu gösterimleri yuvarlama hatalarına daha açık hale getirir.

İkili bir işlecin işlenenlerinden herhangi biri decimal türünde ise, §12.4.7'de ayrıntılı olarak açıklandığı gibi standart sayısal yükseltmeler uygulanır ve işlem double hassasiyetiyle gerçekleştirilir.

Tür decimal değerleri üzerindeki bir işlemin sonucu, tam sonucun hesaplanmasından (her işleç için tanımlandığı gibi ölçeğin korunması) ve ardından gösterimi sığdırmak için yuvarlamanın sonucudur. Sonuçlar en yakın temsil edilebilen değere yuvarlanır ve bir sonuç iki temsil edilebilen değere eşit derecede yakınsa, en az anlamlı basamak konumunda çift sayıya sahip olan değere (ki bu "bankacı yuvarlaması" olarak bilinir) yuvarlanır. Yani, sonuçlar en az 28. ondalık basamağa kadar kesinlik gösterir. Yuvarlamanın sıfır olmayan bir değerden sıfır değeri üretebileceğini unutmayın.

Aritmetik bir decimal işlem, büyüklüğü biçim için decimal çok büyük olan bir sonuç üretirse, bir System.OverflowException oluşturulur.

Türün decimal duyarlığı daha yüksektir, ancak kayan nokta türlerinden daha küçük bir aralığa sahip olabilir. Bu nedenle, kayan nokta türlerinden decimal dönüştürmeler taşma özel durumları üretebilir ve decimal'den kayan nokta türlerine dönüştürmeler duyarlık kaybına veya taşma özel durumlarına neden olabilir. Bu nedenlerden dolayı, kayan nokta türleri ile decimal arasında örtük dönüşümler yoktur ve açık dönüşümler olmadan, kayan nokta ve decimal işleçleri aynı ifadede doğrudan karıştırıldığında derleme zamanı hatası oluşur.

8.3.9 Bool türü

türü Boole bool mantıksal miktarlarını temsil eder. Türün bool olası değerleri true ve false'dir. temsili false§8.3.3'te açıklanmıştır. true'nin gösterimi belirtilmemiş olsa da, false'nin gösteriminden farklı olacaktır.

bool ve diğer değer türleri arasında standart dönüşümler mevcut değil. Özellikle, bool türü belirgin ve ayrı olup, integral türlerinden ayrıdır; bir bool değer, tam sayı değeri yerine kullanılamaz ve tam tersi de geçerli değildir.

Not: C ve C++ dillerinde sıfır integral veya kayan nokta değeri ya da null işaretçi Boole değerine false, sıfır olmayan integral veya kayan nokta değerine dönüştürülebilir ya da null olmayan bir işaretçi Boole değerine truedönüştürülebilir. C# dilinde bu tür dönüştürmeler, bir integral veya kayan nokta değeri açıkça sıfırla karşılaştırılarak veya nesne başvurusu açıkça null ile karşılaştırılarak gerçekleştirilir. dipnot

8.3.10 Numaralandırma türleri

Numaralandırma türü, adlandırılmış sabitleri olan ayrı bir türdür. Her sabit listesi türü, byte, sbyte, short, ushort, int, uint, long veya ulong şeklinde temel bir türe sahip olmalıdır. Numaralandırma türünün değer kümesi, temel alınan türün değer kümesiyle aynıdır. Numaralandırma türünün değerleri adlandırılmış sabitlerin değerleriyle sınırlı değildir. Numaralandırma türleri, numaralandırma bildirimleri (§19.2) aracılığıyla tanımlanır.

8.3.11 Tanımlama Grubu türleri

Tanımlama grubu türü, isteğe bağlı adlara ve tek tek türlere sahip sıralı, sabit uzunlukta bir değer dizisini temsil eder. Bir tanımlama grubu türündeki öğelerin sayısı, onun arity değeri olarak adlandırılır. Tanımlama grubu türü n ≥ 2 ile yazılır (T1 I1, ..., Tn In) ; burada tanımlayıcılar I1...In isteğe bağlı tanımlama grubu öğe adlarıdır.

Bu söz dizimi, türü ile yapılandırılmış bir türün T1...TnSystem.ValueTuple<...>kısaltmasıdır. Bu, iki ile yedi arasında (dahil) herhangi bir demet türünü doğrudan ifade edebilen bir dizi genel yapı türü olacaktır. Herhangi bir System.ValueTuple<...> tanımlama grubu türünün arlığına karşılık gelen sayıda tür parametresiyle doğrudan eşleşen bir bildirim olması gerekmez. Bunun yerine, yedi veya daha fazla elemanlı demetler, demet öğelerine ek olarak, farklı bir System.ValueTuple<T1, ..., T7, TRest> türü kullanarak kalan öğelerin iç içe değerini kapsayan Rest alanına sahip genel bir yapı türü System.ValueTuple<...> ile temsil edilir. Bu tür iç içe geçme, örneğin bir Rest alanın varlığı yoluyla çeşitli şekillerde gözlemlenebilir. Yalnızca tek bir ek alanın gerekli olduğu durumlarda, genel yapı türü System.ValueTuple<T1> kullanılır; bu tür kendi içinde kümelenmiş tür olarak kabul edilmez. Yediden fazla ek alan gerektiğinde, System.ValueTuple<T1, ..., T7, TRest> özyinelemeli olarak kullanılır.

Bir tanımlama grubu türü içindeki öğe adları ayrı olmalıdır. formunItemXX, bir tanımlama grubu öğesinin konumunu temsil edebilen başlatılmamış ondalık basamaklardan oluşan0 herhangi bir dizi olduğu bir tanımlama grubu öğesi adı, yalnızca tarafından Xbelirtilen konumda izin verilir.

İsteğe bağlı öğe adları türlerde ValueTuple<...> gösterilmez ve tanımlama grubu değerinin çalışma zamanı gösteriminde depolanmaz. Kimlik dönüştürmeleri (§10.2.2) öğe türlerinin kimlik dönüştürülebilir dizilerine sahip tanımlama kümeleri arasında bulunur.

new §12.8.17.2 işleci tuple türü söz dizimi new (T1, ..., Tn) ile uygulanamaz. Tanımlama grubu değerleri tanımlama grubu ifadelerinden (§12.8.6) veya işleci doğrudan öğesinden newoluşturulan bir türe uygulanarak ValueTuple<...> oluşturulabilir.

Tuple öğeleri, Item1, Item2 gibi adlarla genel alanlardır ve bir tuple değeri üzerindeki üye erişimi (§12.8.7) yoluyla erişilebilir. Ayrıca, demet türünün bir öğenin adı varsa, o öğeye erişmek için bu ad kullanılabilir.

Not: Büyük tanımlama grupları iç içe System.ValueTuple<...> değerlerle temsil edilse bile, her tanımlama grubu öğesine konumuna Item... karşılık gelen adla doğrudan erişilebilir. dipnot

Örnek: Aşağıdaki örnekler verilmiştir:

(int, string) pair1 = (1, "One");
(int, string word) pair2 = (2, "Two");
(int number, string word) pair3 = (3, "Three");
(int Item1, string Item2) pair4 = (4, "Four");
// Error: "Item" names do not match their position
(int Item2, string Item123) pair5 = (5, "Five");
(int, string) pair6 = new ValueTuple<int, string>(6, "Six");
ValueTuple<int, string> pair7 = (7, "Seven");
Console.WriteLine($"{pair2.Item1}, {pair2.Item2}, {pair2.word}");

pair1, pair2 ve pair3 için tanımlama grubu türlerinin hepsi geçerlidir; tanımlama grubu türü öğelerinin hiçbirine, bazısına veya tümüne ad verilebilir.

Adların pair4 ve konumlarının eşleşmesi nedeniyle için tanımlama grubu türü Item1 geçerlidir, ancak adlar Item2 ve pair5Item2 eşleşmediğinden için tanımlama grubu türüne Item123 izin verilmez.

pair6 ve pair7 bildirimleri, tanım grubu türlerinin ValueTuple<...> formundan oluşturulmuş türlerle değiştirilebilir olduğunu ve new işleminin bu türlerle kullanıldığı söz dizimine izin verildiğini gösterir.

Son satır, demet öğelerine, konumlarına karşılık gelen isimle veya türde mevcutsa ilgili demet öğesi ismiyle erişilebileceğini Item gösterir. son örnek

8.3.12 Null değer türleri

Null atanabilir bir değer türü, temel alınan türün tüm değerlerini ve ek bir null değeri temsil edebilir. Null atanabilir bir değer türü yazılır T?; burada T temel alınan türdür. Bu söz dizimi için System.Nullable<T>kısaltmadır ve iki form birbirinin yerine kullanılabilir.

Buna karşılık, boş değer atanamayan bir değer türü, ve onun kısaltması (herhangi bir System.Nullable<T> için) dışındaki herhangi bir değer türü, ayrıca boş değer atanamayan bir değer türü olarak kısıtlanan herhangi bir tür parametresidir (yani, değer türü kısıtlaması olan herhangi bir tür parametresi (T?)). System.Nullable<T> türü, T için değer türü kısıtlamasını belirtir; bu, null atanabilir bir değer türünün temel türünün boş değer atanamayan herhangi bir değer türü olabileceği anlamına gelir. Null atanabilir bir değer türünün temel türü, null atanabilir bir değer türü veya başvuru türü olamaz. Örneğin, int?? geçersiz bir türdür. Null değer alabilen başvuru türleri §8.9 kapsamındadır.

Null atanabilir bir değer türünün T? örneği iki genel salt okunur özelliğe sahiptir:

  • HasValue Türün özelliğibool
  • Value Türün özelliğiT

Örneğin HasValuetrue null olmayan olduğu söylenir. Null olmayan bir örnek bilinen bir değer içerir ve Value bu değeri döndürür.

Bir örnekte HasValuefalse ise, o örneğin null olduğu söylenir. Null örnek tanımlanmamış bir değere sahiptir. Null örneğinin Value okunmaya çalışılması, bir System.InvalidOperationException atılmasına sebep olur. Null atanabilir bir örneğin Value özelliğine erişme işlemi, unwrapping olarak adlandırılır.

Varsayılan oluşturucuya ek olarak, her null atanabilir değer türünün T? türünde Ttek bir parametresi olan bir ortak oluşturucu vardır. Bir değer x türünde T verildiğinde, formun oluşturucu çağrısı

new T?(x)

T? olan, Value özelliği x olan null olmayan bir örnek oluşturur. Belirli bir değer için null değer türünün null olmayan bir örneğini oluşturma işlemi sarmalama olarak adlandırılır.

Örtük dönüştürmeler, null literali ile T? arasında (§10.2.7) ve T ile T? arasında (§10.2.6) kullanılabilir.

Null atanabilir değer türü T? arabirim uygulamaz (§18). Özellikle bu, temel alınan türün T uyguladığı hiçbir arabirimi uygulamadığı anlamına gelir.

8.3.13 Kutulama ve kutu açma

Kutulama ve kutudan çıkarma kavramı, herhangi bir value_type değerinin türünü reference_type ve value_type değerine dönüştürülmesine izin vererek, bu iki tür arasında bir köprü oluşturur. Kutulama ve kutu açma, herhangi bir türdeki bir değerin nihayetinde bir object olarak görülebileceği birleşik bir tür sistemini etkinleştirir.

Boks §10.2.9'da daha ayrıntılı olarak açıklanmıştır ve kutu açma §10.3.7'de açıklanmıştır.

8.4 Yapılı türler

8.4.1 Genel

Genel tür bildirimi, tür argümanlarını uygulayarak birçok farklı tür oluşturmak için "taslak" olarak kullanılan bağlanmamış bir genel türü kendi başına belirtir. Tür bağımsız değişkenleri, genel türün adının hemen ardından açılı ayraçlar (< ve >) içinde yazılır. En az bir tür bağımsız değişkeni içeren türlere oluşturulmuş tür denir. Yapıtlı tür, dildeki bir tür adının görüntülenebildiği çoğu yerde kullanılabilir. İlişkisiz genel tür yalnızca bir typeof_expression içinde kullanılabilir (§12.8.18).

Oluşturulmuş türler, ifadelerde basit isimler (§12.8.4) veya bir üyeye erişirken (§12.8.7) de kullanılabilir.

Bir namespace_or_type_name değerlendirildiğinde, yalnızca doğru tür parametresi sayısına sahip genel türler dikkate alınır. Bu nedenle, türlerde farklı sayıda tür parametresi olduğu sürece, farklı türleri tanımlamak için aynı tanımlayıcıyı kullanmak mümkündür. Bu, aynı programdaki genel ve genel olmayan sınıfları karıştırırken kullanışlıdır.

Örnek:

namespace Widgets
{
    class Queue {...}
    class Queue<TElement> {...}
}

namespace MyApplication
{
    using Widgets;

    class X
    {
        Queue q1;      // Non-generic Widgets.Queue
        Queue<int> q2; // Generic Widgets.Queue
    }
}

son örnek

namespace_or_type_name üretimlerinde ad araması için ayrıntılı kurallar §7.8'de açıklanmıştır. Bu üretimlerdeki belirsizliklerin çözümü §6.2.5'te açıklanmıştır. Bir type_name, tür parametrelerini doğrudan belirtmese bile, bir yapı türü tanımlayabilir. Bu durum, bir türün genel class bir bildirimin içinde iç içe geçtiği ve içeren bildirimin örnek türünün ad araması (§15.3.9.7) için örtük olarak kullanıldığı durumlarda oluşabilir.

Örnek:

class Outer<T>
{
    public class Inner {...}

    public Inner i; // Type of i is Outer<T>.Inner
}

son örnek

Enum olmayan bir yapısal tür unmanaged_type (§8.8) olarak kullanılmamalıdır.

8.4.2 Tür bağımsız değişkenleri

Tip bağımsız değişkeni listesindeki her bir bağımsız değişken sadece bir tiptir.

type_argument_list
    : '<' type_argument (',' type_argument)* '>'
    ;

type_argument
    : type
    | type_parameter nullable_type_annotation?
    ;

Her tür bağımsız değişken, karşılık gelen tür parametresindeki (§15.2.5) kısıtlamaları karşılamalıdır. Tür parametresinin null atanabilirliği ile eşleşmeyen bir başvuru türü bağımsız değişkeni, yine de kısıtlamayı karşılar; ancak bir uyarı verilebilir.

8.4.3 Açık ve kapalı türler

Tüm türler açık türler veya kapalı türler olarak sınıflandırılabilir. Açık tür, tür parametrelerini içeren bir türdür. Daha açık belirtmek gerekirse:

  • Tür parametresi açık bir tür tanımlar.
  • Dizi türü, yalnızca öğe türü açık bir türse açık bir türdür.
  • Bir yapılı tür, ancak ve ancak tür bağımsız değişkenlerinden biri veya daha fazlası açık bir tür olduğunda açık bir türdür. İç içe geçen bir tür, yalnızca kendi tür bağımsız değişkenlerinden biri veya daha fazlası ya da içeren türlerden birinin tür bağımsız değişkenleri açık bir tür olduğunda açık bir türdür.

Kapalı tür, açık bir tür olmayan bir türdür.

Çalışma zamanında, genel tür bildirimi içindeki kodun tümü, genel bildirime tür argümanları uygulanarak oluşturulan tamamlanmış yapılandırılmış tür bağlamında yürütülür. Genel türdeki her tür parametresi belirli bir çalışma zamanı türüne bağlıdır. Tüm deyim ve ifadelerin çalışma zamanı işlemesi her zaman kapalı türlerle gerçekleşir ve açık türler yalnızca derleme zamanı işleme sırasında gerçekleşir.

İki kapalı yapı türü, aynı kapsamsız genel türden oluşturulmuşlarsa ve karşılık gelen tür parametrelerinin her biri arasında bir kimlik dönüşümü mevcutsa, kimlik dönüşümü yapılabilir (§10.2.2). Karşılık gelen tür bağımsız değişkenleri, kimliği dönüştürülebilir olan, kendilerinden ayrılmış türler veya tanımlama kümeleri olabilir. Kimliği dönüştürülebilir olan kapalı yapılı türler tek bir statik değişken kümesini paylaşır. Aksi takdirde, kapatılan her tür kendi statik değişken kümesine sahiptir. Çalışma zamanında açık bir tür olmadığından, açık bir türle ilişkili statik değişken yoktur.

8.4.4 İlişkili ve ilişkisiz türler

İlişkisiz tür terimi genel olmayan bir türe veya ilişkisiz genel türe başvurur. İlişkili tür terimi genel olmayan bir türe veya bir yapı türüne başvurur.

Bağlı olmayan bir tür, tür bildirimi ile ilan edilen varlığa işaret eder. İlişkisiz genel tür kendisi bir tür değildir ve değişken türü, bağımsız değişken veya dönüş değeri olarak ya da temel tür olarak kullanılamaz. İlişkisiz genel türe başvurulabilecek tek yapı ifadedir typeof (§12.8.18).

8.4.5 Kısıtlamaları karşılama

Bir yapılandırılmış tür veya genel yönteme her başvurulduğunda, verilen tür bağımsız değişkenleri, genel tür veya yöntem üzerinde belirtilen tür parametresi kısıtlamalarına göre kontrol edilir (§15.2.5). Her where koşul için, adlandırılmış tür parametresine karşılık gelen tür bağımsız değişkeni A aşağıdaki gibi her kısıtlamaya karşı denetlenir.

  • Kısıtlama bir class türü, bir arabirim türü veya tür parametresiyse, kısıtlamada geçen tür parametrelerinin yerine geçen sağlanan tür argümanlarıyla C'i temsil et. Kısıtlamayı karşılamak için, türün A aşağıdakilerden birine göre türe C dönüştürülebilir olması gerekir:
    • Kimlik dönüştürme (§10.2.2)
    • Örtük referans dönüştürmesi (§10.2.8)
    • Bir "boxing conversion" (§10.2.9), bu tür A null atanamaz bir değer türü olması koşuluyla.
    • Bir tür parametresinden A öğesine örtük başvuru, kutulama veya tür parametresi C dönüştürmesi.
  • Kısıtlama başvuru türü kısıtlaması ()class ise, tür A aşağıdakilerden birini karşılamalı:
    • A bir arabirim türü, sınıf türü, temsilci türü, dizi türü veya dinamik türdür.

    Not: System.ValueType ve System.Enum bu kısıtlamayı karşılayan başvuru türleridir. dipnot

    • A , başvuru türü (§8.2) olarak bilinen bir tür parametresidir.
  • Kısıtlama değer türü kısıtlaması ()struct ise, tür A aşağıdakilerden birini karşılamalı:
    • A bir struct tür veya enum türdür, ancak null atanabilir bir değer türü değildir.

    Not: System.ValueType ve System.Enum bu kısıtlamayı karşılamayan başvuru türleridir. dipnot

    • A değer türü kısıtlamasını (§15.2.5) içeren bir tür parametresidir.
  • Eğer kısıtlama oluşturucu kısıtlaması new() ise, türü Aabstract olmamalıdır ve genel parametresiz bir oluşturucuya sahip olmalıdır. Aşağıdakilerden biri doğruysa bu durum geçerlidir:
    • A bir değer türüdür, çünkü tüm değer türlerinin bir ortak varsayılan oluşturucu (§8.3.3) vardır.
    • A , oluşturucu kısıtlamasını (§15.2.5) içeren bir tür parametresidir.
    • A değer türü kısıtlamasını (§15.2.5) içeren bir tür parametresidir.
    • A soyut olmayan ve parametresiz açıkça bildirilen genel bir oluşturucu içeren bir class'dir.
    • A değildir abstract ve varsayılan bir oluşturucuya sahiptir (§15.11.5).

Bir tür parametresinin kısıtlamalarından biri veya daha fazlası verilen tür bağımsız değişkenleri tarafından karşılanmazsa derleme zamanı hatası oluşur.

Tür parametreleri devralınmadığından, kısıtlamalar da hiçbir zaman devralınmaz.

Örnek: Aşağıda, D türü parametresi üzerinde T kısıtlamayı belirleyerek T'ün, temel classB<T> tarafından uygulanan kısıtlamayı karşılaması ihtiyacı vardır. Buna karşılık, classE herhangi bir için uygulandığından List<T> kısıtlama IEnumerable belirtmeye gerek yokturT.

class B<T> where T: IEnumerable {...}
class D<T> : B<T> where T: IEnumerable {...}
class E<T> : B<List<T>> {...}

son örnek

8.5 Tür parametreleri

Tür parametresi, parametrenin çalışma zamanında bağlı olduğu bir değer türünü veya başvuru türünü belirten bir tanımlayıcıdır.

type_parameter
    : identifier
    ;

Bir tür parametresinin örneği birçok farklı tür bağımsız değişkeniyle oluşturulabildiğinden, tür parametreleri diğer türlerden biraz farklı işlemlere ve kısıtlamalara sahiptir.

Not: Bunlar şunlardır:

  • Tür parametresi, bir temel sınıfı (§15.2.4.2) veya arabirimi (§18.2.4) bildirmek için doğrudan kullanılamaz.
  • Tür parametrelerinde üye arama kuralları, tür parametresine uygulanan kısıtlamalara (varsa) bağlıdır. Bunlar §12.5'te ayrıntılı olarak yer alır.
  • Tür parametresi için kullanılabilir dönüştürmeler, tür parametresine uygulanan kısıtlamalara (varsa) bağlıdır. Bunlar §10.2.12 ve §10.3.8 ile ayrıntılı olarak anlatılır.
  • Tür null parametresinin başvuru türü (§10.2.12) olarak bilinmesi dışında değişmez değer, tür parametresi tarafından verilen türe dönüştürülemez. Ancak, bunun yerine varsayılan ifade (§12.8.21) kullanılabilir. Ayrıca, değer türü kısıtlaması olmadığı sürece, tür parametresi tarafından verilen türe sahip bir değer karşılaştırılabilir== ve != kullanılarak null ile (§12.12.7).
  • İfade new (§12.8.17.2), yalnızca tür parametresi bir constructor_constraint veya değer türü kısıtlaması (§15.2.5) ile kısıtlanmışsa tür parametresiyle kullanılabilir.
  • Tür parametresi öznitelik içinde herhangi bir yerde kullanılamaz.
  • Tür parametresi, statik bir üyeyi veya iç içe türü tanımlamak için üye erişiminde (§12.8.7) veya tür adında (§7.8) kullanılamaz.
  • Tür parametresi unmanaged_type (§8.8) olarak kullanılamaz.

dipnot

Tür olarak, tür parametreleri yalnızca bir derleme zamanı yapısıdır. Çalışma zamanında, her tip parametresi, genel tip bildirimine bir tip argümanı sağlayarak belirlenen bir çalışma zamanı tipine bağlıdır. Bu nedenle, tür parametresiyle bildirilen bir değişkenin türü, çalışma zamanında , §8.4.3 kapalı bir tür olarak oluşturulacaktır. Tür parametreleriyle ilgili tüm deyimlerin ve ifadelerin çalışma zamanı yürütmesi, bu parametre için tür bağımsız değişkeni olarak sağlanan türü kullanır.

8.6 İfade ağacı türleri

İfade ağaçları , lambda ifadelerinin yürütülebilir kod yerine veri yapıları olarak temsil edilmesine izin verir. İfade ağaçları, herhangi bir temsilci türü olan formun System.Linq.Expressions.Expression<TDelegate> değerleridir. Bu belirtimin geri kalanı için bu türlere kısaltması Expression<TDelegate>kullanılarak başvurulacaktır.

Lambda ifadesinden temsilci türüne Ddönüştürme varsa, ifade ağacı türüne Expression<TDelegate>dönüştürme de vardır. Lambda ifadesinin temsilci türüne dönüştürülmesi lambda ifadesi için yürütülebilir koda başvuran bir temsilci oluştururken, ifade ağacı türüne dönüştürme, lambda ifadesinin ifade ağacı gösterimini oluşturur. Bu dönüştürmenin diğer ayrıntıları §10.7.3'te sağlanmıştır.

Örnek: Aşağıdaki program bir lambda ifadesini hem yürütülebilir kod hem de ifade ağacı olarak temsil eder. dönüştürmesi Func<int,int>olduğundan, için bir dönüştürme de vardır Expression<Func<int,int>>:

Func<int,int> del = x => x + 1;             // Code
Expression<Func<int,int>> exp = x => x + 1; // Data

Bu atamaların ardından temsilci del , döndüren x + 1bir yönteme başvurur ve ifade ağacı exp ifadesi ifadesini açıklayan bir veri yapısına x => x + 1başvurur.

son örnek

Expression<TDelegate>, Compile türünde bir temsilci üreten bir örnek yöntemi TDelegate sağlar.

Func<int,int> del2 = exp.Compile();

Bu temsilciyi çağırmak, ifade ağacı tarafından temsil edilen kodun yürütülmesine neden olur. Bu nedenle, yukarıdaki del tanımları dikkate alır ve del2 eşdeğerdir ve aşağıdaki iki deyim aynı etkiye sahip olur:

int i1 = del(1);
int i2 = del2(1);

Bu kodu i1 yürüttkten sonra ve i2 her ikisi de değerine 2sahip olur.

tarafından Expression<TDelegate> sağlanan API yüzeyi, yukarıda açıklanan bir Compile yöntem gereksiniminin ötesinde uygulama tanımlıdır.

Not: İfade ağaçları için sağlanan API'nin ayrıntıları uygulama tanımlı olsa da, bir uygulamanın şunları gerçekleştirmesi beklenir:

  • Bir lambda ifadesinden dönüştürmenin sonucu olarak oluşturulan bir ifade ağacının yapısını incelemek ve yanıtlamak için kodu etkinleştirme
  • kullanıcı kodu içinde programlı olarak oluşturulacak ifade ağaçlarını etkinleştirme

dipnot

8.7 Dinamik tür

Türü dynamic , diğer tüm türler tarafından kullanılan statik bağlamanın aksine , §12.3.2'de ayrıntılı olarak açıklandığı gibi dinamik bağlama kullanır.

Türü dynamic , aşağıdakiler dışında ile özdeş object olarak kabul edilir:

  • Tür dynamic ifadelerindeki işlemler dinamik olarak bağlanabilir (§12.3.3).
  • Tür çıkarımı (§12.6.3), her ikisi de aday olduğunda dynamic'i object'e tercih edecektir.
  • dynamic olarak kullanılamaz
    • object_creation_expression türü (§12.8.17.2)
    • class_base (§15.2.4)
    • predefined_type bir member_access içinde (§12.8.7.1)
    • işleç typeof operatörünün işleneni
    • özellik argümanı
    • kısıtlama
    • uzantı yöntemi türü
    • struct_interfaces (§16.2.5) veya interface_type_list (§15.2.4.1) içindeki tür bağımsız değişkeninin herhangi bir bölümü.

Bu denklik nedeniyle, aşağıdakiler şunları tutar:

  • Örtük kimlik dönüştürmesi var
    • arasında object ve dynamic
    • dynamic ile object değiştirildiğinde aynı olan yapılı türler arasında
    • ile değiştirirken dynamic aynı olan tanımlama grubu türleri arasında object
  • object ve dynamic'e ve bunlardan örtük ve açık dönüştürmeler de geçerlidir.
  • ile dynamic değiştirilirken object aynı olan imzalar aynı imza olarak kabul edilir.
  • Türü dynamic , çalışma zamanında türünden object ayırt edilemez.
  • Türündeki dynamic bir ifade dinamik ifade olarak adlandırılır.

8.8 Yönetilmeyen türler

unmanaged_type
    : value_type
    | pointer_type     // unsafe code support
    ;

unmanaged_type, ne bir reference_type ne de yönetilmeyen olma zorunluluğu olmayan bir type_parameter olan ve türü unmanaged_typeolmayan örnek alanları içermeyen herhangi bir türdür. Başka bir deyişle, unmanaged_type aşağıdakilerden biridir:

  • sbyte, , byte, , short, ushort, int, , uint, long, ulong, char, floatdoubleveya decimal. bool
  • Herhangi bir enum_type.
  • Kullanıcı tanımlı struct_type, yalnızca unmanaged_typeörnek alanlarını içerir.
  • Yönetilmeyen olarak kısıtlanmış herhangi bir tür parametresi.
  • Herhangi bir pointer_type (§23.3).

8.9 Başvuru Türleri ve null olabilme durumu

8.9.1 Genel

Null atanabilir başvuru türü, null atanamayan başvuru türünebir nullable_type_annotation (?) eklenerek belirtilir. Boş değer atanamayan başvuru türü ile karşılık gelen null atanabilir türü arasında anlamsal bir fark yoktur; her ikisi de bir nesneye veya nullbaşvurusu olabilir. nullable_type_annotation varlığı veya yokluğu, ifadenin null değerlere izin verip vermediğini bildirir. Bir ifade bu amaca göre kullanılmadığında derleyici tanılama sağlayabilir. İfadenin null durumu §8.9.5 içinde tanımlanır. Null atanabilir başvuru türü ve karşılık gelen null atanamaz başvuru türü (§10.2.2) arasında bir kimlik dönüştürmesi vardır.

Başvuru türleri için iki null değeri alabilirlik biçimi vardır.

  • nullable: Bir nullable referans türü olarak atanabilir null. Varsayılan null durumu belki-null'tır.
  • null olmayan: Null olmayan referansa değer null atanmamalıdır. Varsayılan null durumu null değil.

Not: ve R türleriR?, aynı temel türüyle Rtemsil edilir. Bu temel türün değişkeni bir nesneye başvuru içerebilir veya değeri nullolabilir ve bu değer "başvuru yok" ifadesini gösterir. dipnot

Null atanabilir başvuru türü ile karşılık gelen null atanamayan başvuru türü arasındaki sözdizimsel ayrım, derleyicinin tanılama mesajları üretmesine olanak tanır. Bir derleyici, §8.2.1'de tanımlandığı gibi nullable_type_annotation olarak izin vermelidir. Tanılamalar uyarılarla sınırlı olmalıdır. Ne boş değer atanabilir ek açıklamaların varlığı ne de yokluğu ve ne de boş değer atanabilir bağlamın durumu, derleme zamanında oluşturulan tanılama iletilerindeki değişiklikler haricinde, bir programın derleme veya çalışma zamanı davranışını değiştiremez.

8.9.2 Null değer atanamayan başvuru türleri

Null atanamayan başvuru türü, T formunda bir başvuru türüdür; burada T türün adıdır. Null değer atanamayan bir değişkenin varsayılan null durumu null değildir. Null olmayan bir değerin gerekli olduğu yerlerde muhtemelen null olan bir ifade kullanıldığında uyarılar oluşturulabilir.

8.9.3 Boş değer atanabilir başvuru türleri

Formu T? olan bir referans türü (örneğin string?), null yapılabilir bir referans türüdür. Null atanabilir bir değişkenin varsayılan null durumu null olabilir. Ek açıklamalar ? , bu türdeki değişkenlerin null olabileceğini belirtir. Derleyici, uyarı vermek için bu amaçları tanıyabilir. Boş değer atanabilir ek açıklama bağlamı devre dışı bırakıldığında, bu ek açıklamayı kullanmak bir uyarı oluşturabilir.

8.9.4 Null atanabilir bağlam

8.9.4.1 Genel

Her kaynak kodu satırının boş değer atanabilir bir bağlamı vardır. Nullable bağlam kontrolü için anotasyonlar (§8.9.4.3) ve nullable uyarılar (§8.9.4.4) için bayraklar sırasıyla. Her bayrak etkinleştirilebilir veya devre dışı bırakılabilir. Derleyici, herhangi bir başvuru değişkeninin null durumunu belirlemek için statik akış analizini kullanabilir. Başvuru değişkeninin null durumu (§8.9.5) null değil, belki null veya belki de varsayılan.

Nullable bağlam, kaynak kodu üzerinde nullable yönergeler (§6.5.9) ve/veya kaynak kodun dışındaki uygulamaya özgü bir mekanizma aracılığıyla belirtilebilir. Her iki yaklaşım da kullanılırsa, boş kabul edilebilir yönergeler, bir dış mekanizma aracılığıyla yapılan ayarları geçersiz kılar.

Null atanabilir bağlamın varsayılan durumu uygulamaya bağlıdır.

Bu tanım boyunca, boş değer atanabilir yönergeler içermeyen veya mevcut null atanabilir bağlam durumu hakkında bir ifade bulunmayan tüm C# kodlarının, hem ek açıklamaların hem de uyarıların etkin olduğu null atanabilir bir bağlamda derlendiği varsayılır.

Not: Her iki bayrağın da devre dışı bırakıldığı null atanabilir bağlam, başvuru türleri için önceki standart davranışla eşleşir. dipnot

8.9.4.2 Null yapılabilir devre dışı bırakma

Hem uyarı hem de ek açıklama bayrakları devre dışı bırakıldığında, null değer atanabilir bağlam devre dışı bırakılır.

Null atanabilir bağlam devre dışı bırakıldığında:

  • Ek açıklaması olmayan başvuru türündeki bir değişken, null ile başlatıldığında veya ona null değeri atandığında uyarı oluşturulmaz.
  • Başvuru türündeki bir değişkenin olasılıkla null değeri varsa uyarı oluşturulmaz.
  • herhangi bir başvuru türü için T, ? içindeki T? ek açıklama bir ileti oluşturur ve türü T?, T ile aynıdır.
  • Herhangi bir tür parametresi kısıtlaması where T : C? için, ? içinde yer alan C? ek açıklaması bir ileti oluşturur ve tür C?, C ile aynıdır.
  • Herhangi bir tür parametresi kısıtlaması where T : U? için, ? içinde yer alan U? ek açıklaması bir ileti oluşturur ve tür U?, U ile aynıdır.
  • Genel kısıtlama class? bir uyarı iletisi oluşturur. Tip parametresi bir referans tipi olmalıdır.

    Not: Bu ileti, "uyarı" yerine "bilgilendirme" olarak nitelenir, bu nedenle bu iletinin ilgisiz olan null atanabilir uyarı ayarının durumuyla karıştırılmaması gerekir. dipnot

  • Null-forgiving işlecinin ! (§12.8.9) hiçbir etkisi yoktur.

Örnek:

#nullable disable annotations
string? s1 = null;    // Informational message; ? is ignored
string s2 = null;     // OK; null initialization of a reference
s2 = null;            // OK; null assignment to a reference
char c1 = s2[1];      // OK; no warning on dereference of a possible null;
                      //     throws NullReferenceException
c1 = s2![1];          // OK; ! is ignored

son örnek

8.9.4.3 Boş değer atanabilir ek açıklamalar

Uyarı bayrağı devre dışı bırakıldığında ve açıklamalar bayrağı etkinleştirildiğinde, null atanabilir bağlam açıklamalar olur.

Null atanabilir bağlam ek açıklamalar olduğunda:

  • herhangi bir başvuru türü T için, ? içindeki ek açıklama T? bir null atanabilir tür olduğunu belirtirken, ek açıklamasız T? null atanamaz.
  • Null değerlerle ilgili tanılama uyarıları üretilmez.
  • Null-forgiving işleci ! (§12.8.9), işlenenin analiz edilmiş null durumunu ve hangi derleme zamanı tanılama uyarılarının üretildiğini değiştirebilir.

Örnek:

#nullable disable warnings
#nullable enable annotations
string? s1 = null;    // OK; ? makes s2 nullable
string s2 = null;     // OK; warnings are disabled
s2 = null;            // OK; warnings are disabled
char c1 = s2[1];      // OK; warnings are disabled; throws NullReferenceException
c1 = s2![1];          // No warnings

son örnek

8.9.4.4 Null olabilen uyarılar

Uyarı bayrağı etkinleştirildiğinde ve ek açıklama bayrağı devre dışı bırakıldığında, null atanabilir bağlam uyarılardır.

Null atanabilir bağlam uyarılar olduğunda, derleyici aşağıdaki durumlarda tanılama oluşturabilir:

  • Belki null olduğu belirlenen bir başvuru değişkeni başvurulmaz.
  • Null olmayan türde bir başvuru değişkeni, null olabilecek bir ifadeye atanır.
  • ? null yapılabilir referans türünü belirtmek için kullanılır.
  • null affeden işleci ! (§12.8.9), işlenenin null durumunu null değil olarak ayarlamak için kullanılır.

Örnek:

#nullable disable annotations
#nullable enable warnings
string? s1 = null;    // OK; ? makes s2 nullable
string s2 = null;     // OK; null-state of s2 is "maybe null"
s2 = null;            // OK; null-state of s2 is "maybe null"
char c1 = s2[1];      // Warning; dereference of a possible null;
                      //          throws NullReferenceException
c1 = s2![1];          // The warning is suppressed

son örnek

8.9.4.5 Null yapılabilirliği etkinleştirme

Hem uyarı bayrağı hem de annotasyon bayrağı etkinleştirildiğinde, null yapılabilir bağlam etkinleştirilir.

Null atanabilir bağlam etkinleştirildiğinde:

  • herhangi bir referans türü T için, ? içindeki T? açıklaması T?'ü null yapılabilir bir tür haline getirir, oysa açıklamasız T non-nullable'dır.
  • Derleyici, herhangi bir başvuru değişkeninin null durumunu belirlemek için statik akış analizini kullanabilir. Null atanabilir uyarılar etkinleştirildiğinde, başvuru değişkeninin null durumu (§8.9.5) null değil, belki null veya belki varsayılan olur.
  • null'u görmezden gelen işleç ! (§12.8.9), işleneninin null durumunu null değil olarak ayarlar.
  • Bir tür parametresinin null durumu, karşılık gelen tür bağımsız değişkeninin null durumu ile eşleşmiyorsa, derleyici uyarı verebilir.

8.9.5 Nullabiliteler ve null durumlar

8.9.5.1 Genel

Derleyicinin statik analiz gerçekleştirmesi veya null atanabilirlikle ilgili tanılama uyarıları oluşturması gerekmez.

Bu alt makalenin geri kalanı koşullu normatiftir.

8.9.5.2 Akış analizi

Tanılama uyarıları oluşturan bir derleyici bu kurallara uygundur.

Her ifadenin üç null durumundanbiri vardır:

  • belki null: İfadenin değeri null olarak değerlendirilebilir.
  • belki de varsayılan: İfadenin değeri, bu tür için varsayılan değer olarak değerlendirilebilir.
  • not null: İfadenin değeri null değil.

İfadenin varsayılan null durumu türüne ve bildirildiğinde ek açıklama bayrağının durumuna göre belirlenir:

  • Null atanabilir referans türünün varsayılan null durumu:
    • Bildirimi, ek açıklama bayrağının etkinleştirildiği metinde olduğunda null olabilir.
    • Bildirimi, ek açıklama bayrağının devre dışı bırakıldığı metinde olduğunda null değil.
  • Null olamayan referans türünün varsayılan null durumu null değildir.

Not: belirsiz varsayılan string, türün null değer atanamayan bir tür olması ve ifadenin default(T) null değer olması durumunda, kısıtlanmamış tür parametreleriyle kullanılır. Null değer atanamayan tür için etki alanında null olmadığından, durum belki de varsayılandır. dipnot

Boş değer atanamayan bir başvuru türünün değişkeni (§9.2.1) başlatıldığında veya bir null değere sahip olabilecek bir ifadeye atandığında ve bu değişkenin ek açıklama bayrağının etkin olduğu bir metinde bildirildiğinde bir tanı oluşturulabilir.

Örnek: Bir parametrenin null atanabilir olduğu ve bu değerin null atanamayan bir türe atandığı aşağıdaki yöntemi göz önünde bulundurun:

#nullable enable
public class C
{
    public void M(string? p)
    {
        // Warning: Assignment of maybe null value to non-nullable variable
        string s = p;
    }
}

Derleyici, null olmayabilecek parametrenin null olmaması gereken bir değişkene atandığı bir uyarı verebilir. Parametre, atamadan önce null kontrolüne tabi tutulursa, derleyici bunu null yapılabilirlik durumu çözümlemesinde kullanabilir ve uyarıda bulunmayabilir.

#nullable enable
public class C
{
    public void M(string? p)
    {
        if (p != null)
        {
            string s = p; // No warning
            // Use s
        }
    }
}

son örnek

Derleyici, çözümlemesinin bir parçası olarak değişkenin null durumunu güncelleştirebilir.

Örnek: Derleyici, programınızdaki deyimleri temel alarak durumu güncelleştirmeyi seçebilir:

#nullable enable
public void M(string? p)
{
    int length = p.Length; // Warning: p is maybe null

    string s = p; // No warning. p is not null

    if (s != null)
    {
        int l2 = s.Length; // No warning. s is not null
    }
    int l3 = s.Length; // Warning. s is maybe null
}

Önceki örnekte, bir derleyici int length = p.Length;deyiminden sonra, p null durumunun null olmadığını karar verebilir. Null olsaydı, bu deyim bir NullReferenceExceptionoluştururdu. Bu, koddan önce if (p == null) throw NullReferenceException(); gelen davranışa benzer, ancak yazılan kod bir uyarı üretebilir ve bunun amacı örtük olarak bir özel durumun oluşturulabileceği konusunda uyarmaktır. son örnek

Yöntemin ilerleyen bölümlerinde kod, s'nin null başvuru olup olmadığını denetler. s'nin null durumu, null kontrolü yapılmış blok kapandıktan sonra belki null olarak değişebilir. Kodun null olabileceği varsayılarak yazılmış olduğu için, derleyici s'ın null olabileceğini çıkarabilir. Genellikle, kod null denetimi içerdiğinde, derleyici değerin null olabileceğini çıkarsayabilir:

Örnek: Aşağıdaki ifadelerin her biri null denetimin bir biçimini içerir. o'ın boş durumu, her bir ifadenin ardından boş değil durumundan belki boş hale gelebilir.

#nullable enable
public void M(string s)
{
    int length = s.Length; // No warning. s is not null

    _ = s == null; // Null check by testing equality. The null state of s is maybe null
    length = s.Length; // Warning, and changes the null state of s to not null

    _ = s?.Length; // The ?. is a null check and changes the null state of s to maybe null
    if (s.Length > 4) // Warning. Changes null state of s to not null
    {
        _ = s?[4]; // ?[] is a null check and changes the null state of s to maybe null
        _ = s.Length; // Warning. s is maybe null
    }
}

Hem otomatik özellik hem de alan benzeri olay bildirimleri, derleyici tarafından oluşturulan bir yedekleme alanını kullanır. Null durum analizi, olay veya özelliğe yapılan atamanın derleyici tarafından oluşturulan bir yedekleme alanına yapılan atama olduğunu çıkarsayabilir.

Örnek: Bir derleyici, otomatik bir özellik veya alan benzeri bir etkinliği yazmanın karşılık gelen derleyici tarafından oluşturulan arka plan alanını yazdığını belirleyebilir. Özelliğin null durumu, yedekleme alanının durumuyla eşleşir.

class Test
{
    public string P
    {
        get;
        set;
    }

    public Test() {} // Warning. "P" not set to a non-null value.

    static void Main()
    {
        var t = new Test();
        int len = t.P.Length; // No warning. Null state is not null.
    }
}

Önceki örnekte, oluşturucu P'yu null olmayan bir değere ayarlamaz, bu yüzden derleyici bir uyarı verebilir. Özelliğin P türü null atanamaz bir başvuru türü olduğundan özelliğe erişildiğinde uyarı olmaz. son örnek

Derleyici bir özelliği (§15.7) durumlu bir değişken olarak veya bağımsız alma ve ayarlama erişimcileri (§15.7.3) olarak değerlendirebilir.

Örnek: Derleyici, bir özelliğe yazmanın özelliği okumanın null durumunu mu değiştireceğini yoksa bir özelliğin okunmasının bu özelliğin null durumunu mu değiştireceğini seçebilir.

class Test
{
    private string? _field;
    public string? DisappearingProperty
    {
        get
        {
            string tmp = _field;
            _field = null;
            return tmp;
        }
        set
        {
            _field = value;
        }
    }

    static void Main()
    {
        var t = new Test();
        if (t.DisappearingProperty != null)
        {
            int len = t.DisappearingProperty.Length; // No warning. A compiler can assume property is stateful
        }
    }
}

Önceki örnekte, DisappearingProperty için yedek alanı okunduğunda null değerine ayarlanır. Ancak, derleyici bir özelliği okumanın bu ifadenin null durumunu değiştirmediğini varsayabilir. son örnek

Derleyici, null durumunu null değil olarak ayarlamak için değişken, özellik veya olayı dereferans eden herhangi bir ifade kullanabilir. Null olsaydı, başvuru kaldırma ifadesi bir NullReferenceExceptionoluştururdu:

Örnek:


public class C
{
    private C? child;

    public void M()
    {
        _ = child.child.child; // Warning. Dereference possible null value
        var greatGrandChild = child.child.child; // No warning. 
    }
}

son örnek

8.9.5.3 Tür dönüştürmeleri

Tanılama uyarıları oluşturan bir derleyici bu kurallara uygundur.

Not: Türlerdeki üst düzey veya iç içe null atanabilirlik açıklamalarındaki farklar, null atanamayan referans türü ile karşılık gelen null atanabilir tür arasında anlamsal bir fark olmadığından, türler arasında dönüştürmeye izin verilip verilmeyeceğini etkilemez. (§8.9.1). dipnot

Derleyici, dönüştürme daraltıldığında, iki tür arasında null atanabilirlik ek açıklamaları ya üst düzey ya da iç içe olarak farklılık gösterdiğinde bir uyarı verebilir.

Örnek: Üst düzey ek açıklamalarda farklılık gösteren türler

#nullable enable
public class C
{
    public void M1(string p)
    {
        _ = (string?)p; // No warning, widening
    }

    public void M2(string? p)
    {
        _ = (string)p; // Warning, narrowing
        _ = (string)p!; // No warning, suppressed
    }
}

son örnek

Örnek: İç içe null atanabilirlik açıklamalarında farklılık gösteren türler

#nullable enable
public class C
{
    public void M1((string, string) p)
    {
        _ = ((string?, string?))p; // No warning, widening
    }

    public void M2((string?, string?) p)
    {
        _ = ((string, string))p; // Warning, narrowing
        _ = ((string, string))p!; // No warning, suppressed
    }
}

son örnek

Derleyici, tür dönüştürmeleri için uyarı verilip verilmeyeceğini belirlemede arabirim varyansı (§18.2.3.3), temsilci varyansı (§20.4) ve dizi kovaryansı (§17.6) kurallarını izleyebilir.

#nullable enable
public class C
{
    public void M1(IEnumerable<string> p)
    {
        IEnumerable<string?> v1 = p; // No warning
    }

    public void M2(IEnumerable<string?> p)
    {
        IEnumerable<string> v1 = p; // Warning
        IEnumerable<string> v2 = p!; // No warning
    }

    public void M3(Action<string?> p)
    {
        Action<string> v1 = p; // No warning
    }

    public void M4(Action<string> p)
    {
        Action<string?> v1 = p; // Warning
        Action<string?> v2 = p!; // No warning
    }

    public void M5(string[] p)
    {
        string?[] v1 = p; // No warning
    }

    public void M6(string?[] p)
    {
        string[] v1 = p; // Warning
        string[] v2 = p!; // No warning
    }
}

son örnek

Derleyici, değişken dönüşümüne izin verilmeyen türlerde her iki yönde de null durumu farklılık gösterdiğinde uyarı verebilir.

#nullable enable
public class C
{
    public void M1(List<string> p)
    {
        List<string?> v1 = p; // Warning
        List<string?> v2 = p!; // No warning
    }

    public void M2(List<string?> p)
    {
        List<string> v1 = p; // Warning
        List<string> v2 = p!; // No warning
    }
}

son örnek

Koşullu normatif metnin sonu