Aracılığıyla paylaş


13 Açıklamalar

13.1 Genel

C# çeşitli ifadeler sağlar.

Not: Bu ifadelerin çoğu C ve C++ ile programlanmış geliştiricilere tanıdık gelecek. dipnot

statement
    : labeled_statement
    | declaration_statement
    | embedded_statement
    ;

embedded_statement
    : block
    | empty_statement
    | expression_statement
    | selection_statement
    | iteration_statement
    | jump_statement
    | try_statement
    | checked_statement
    | unchecked_statement
    | lock_statement
    | using_statement
    | yield_statement
    | unsafe_statement   // unsafe code support
    | fixed_statement    // unsafe code support
    ;

unsafe_statement (§23.2) ve fixed_statement (§23.7) yalnızca güvenli olmayan kodda (§23) kullanılabilir.

embedded_statement non-terminal'ı, diğer deyimler içinde yer alan deyimler için kullanılır. embedded_statement yerine statement kullanımı, bu bağlamlarda bildirim ifadeleri ve etiketli ifadelerin kullanımını dışlar.

Örnek: Kod

void F(bool b)
{
   if (b)
      int i = 44;
}

Bir if ifadesi, dalında bir ifade yerine bir if gerektirdiğinden derleme zamanı hatasına sonuçlanır. Bu koda izin verilseydi değişkeni i bildirilir, ancak hiçbir zaman kullanılamaz. Ancak, i'nın bildirimini bir blok içine yerleştirerek örneğin geçerli olduğunu unutmayın.

son örnek

13.2 Uç noktaları ve ulaşılabilirlik

Her deyimin bir bitiş noktası vardır. Sezgisel anlamda, deyimin bitiş noktası deyiminin hemen ardından gelen konumdur. Bileşik deyimler için yürütme kuralları (katıştırılmış deyimler içeren deyimler), denetim katıştırılmış deyimin bitiş noktasına ulaştığında gerçekleştirilen eylemi belirtir.

Örnek: Denetim bir bloktaki deyimin bitiş noktasına ulaştığında, denetim bloktaki bir sonraki deyime aktarılır. son örnek

Bir deyime yürütme yoluyla ulaşılabiliyorsa, deyimine ulaşılabilir olduğu söylenir. Buna karşılık, bir deyimin yürütülme olasılığı yoksa, deyimin ulaşılamaz olduğu söylenir.

Örnek: Aşağıdaki kodda

void F()
{
    Console.WriteLine("reachable");
    goto Label;
    Console.WriteLine("unreachable");
  Label:
    Console.WriteLine("reachable");
}

Console.WriteLine'ın ikinci çağrısına ulaşılamıyor çünkü deyimin yürütülme olasılığı yok.

son örnek

throw_statement, block veya empty_statement dışındaki bir deyime ulaşılamıyorsa bir uyarı bildirilir. Bir ifadenin erişilemez olması özellikle bir hata değildir.

Not: Belirli bir deyimin veya bitiş noktasının ulaşılabilir olup olmadığını belirlemek için, derleyici her deyim için tanımlanan ulaşılabilirlik kurallarına göre akış analizi gerçekleştirir. Akış analizi, deyimlerin davranışını denetleyen sabit ifadelerin (§12.23) değerlerini dikkate alır, ancak sabit olmayan ifadelerin olası değerleri dikkate alınmaz. Başka bir deyişle, denetim akışı analizi amacıyla, belirli bir türe ait sabit olmayan bir ifadenin bu türdeki herhangi bir olası değere sahip olduğu kabul edilir.

Örnekte

void F()
{
    const int i = 1;
    if (i == 2)
        Console.WriteLine("unreachable");
}

if ifadesinin Boole ifadesi sabit bir ifadedir çünkü == işlecin her iki işleneni de sabittir. Sabit ifade derleme zamanında değerlendirildiğinden, false değeri üretilir ve Console.WriteLine çağrısının ulaşılamaz olduğu kabul edilir. Ancak, yerel değişken olarak değiştirilirse i

void F()
{
    int i = 1;
    if (i == 2)
        Console.WriteLine("reachable");
}

Console.WriteLine çağrının ulaşılabilir olduğu kabul edilir, ancak gerçekte hiçbir zaman yürütülmeyecektir.

dipnot

bir işlev üyesinin veya anonim bir işlevin bloğu her zaman ulaşılabilir olarak kabul edilir. Bloktaki her deyimin ulaşılabilirlik kuralları ardışık olarak değerlendirilerek, belirli bir deyimin erişilebilirliği belirlenebilir.

Örnek: Aşağıdaki kodda

void F(int x)
{
    Console.WriteLine("start");
    if (x < 0)
        Console.WriteLine("negative");
}

ikinci Console.WriteLine ulaşılabilirliği aşağıdaki gibi belirlenir:

  • Yöntemin bloğu ulaşılabilir olduğundan ilk Console.WriteLine ifade deyimine F ulaşılabilir (§13.3).
  • İlk Console.WriteLine ifade deyiminin bitiş noktasına ulaşılabilir çünkü bu deyime ulaşılabilir (§13.7 ve §13.3).
  • if deyimine ulaşılabilir çünkü ilk Console.WriteLine ifade deyiminin bitiş noktasına ulaşılabilir (§13.7 ve §13.3).
  • İkinci Console.WriteLine ifade deyimi, if deyiminin Boole ifadesi sabit bir değer false içermediğinden ulaşılabilir.

son örnek

Deyimin bitiş noktasının ulaşılabilir olması için derleme zamanı hatasının olduğu iki durum vardır:

  • switch deyimi bir switch bölümünün sonraki switch bölümüne "geçmesine" izin vermediğinden, switch bölümünün deyim listesinin bitiş noktasına ulaşılması derleme zamanı hatasıdır. Bu hata oluşursa, genellikle bir break deyiminin eksik olduğunu gösterir.

  • Bu, bir işlev üyesinin bloğunun bitiş noktası veya bir değeri ulaşılabilir olacak şekilde hesaplayan anonim bir işlev için derleme zamanı hatasıdır. Bu hata oluşursa, genellikle bir return deyiminin eksik olduğunun bir göstergesidir (§13.10.5).

13.3 Bloklar

13.3.1 Genel

Blok, birden çok deyimin tek bir deyime izin verilen bağlamlarda yazılmasına izin verir.

block
    : '{' statement_list? '}'
    ;

Bir blok, küme ayraçları içine alınmış opsiyonel bir statement_list (§13.3.2) oluşur. İfadeler listesi atlanırsa, bloğun boş olduğu söylenir.

Blok bildirim deyimleri barındırabilir (§13.6). Yerel değişkenin veya bir blokta bildirilen sabitin kapsamı bloğudur.

Bir blok aşağıdaki gibi yürütülür:

  • Blok boşsa, denetim bloğun bitiş noktasına aktarılır.
  • Blok boş değilse, denetim deyim listesine aktarılır. Denetim, deyim listesinin bitiş noktasına ulaştığında ve eğer ulaşırsa, denetim bloğun bitiş noktasına aktarılır.

Bloğun kendisi ulaşılabilir ise, o bloğun deyim listesi de ulaşılabilir.

Blok boşsa veya deyim listesinin bitiş noktasına ulaşılabilirse bloğun bitiş noktasına ulaşılabilir.

Bir veya daha fazla deyim içeren bir yield (§13.15) yineleyici bloğu olarak adlandırılır. Yineleyici blokları, işlev üyelerini yineleyici olarak uygulamak için kullanılır (§15.15). Yineleyici blokları için bazı ek kısıtlamalar geçerlidir:

  • Bir return deyiminin yineleyici bir blokta görünmesi bir derleme zamanı hatasıdır (ancak yield return deyimlerine izin verilir).
  • Yineleyici bloğunun güvensiz bir bağlam içermesi, derleme zamanında bir hatadır (§23.2). Yineleyici bloğu, bildirimi güvenli olmayan bir bağlamda iç içe yerleştirilmiş olsa bile her zaman güvenli bir bağlam tanımlar.

13.3.2 İfade listeleri

İfade listesi, sırayla yazılmış bir veya daha fazla ifadeden oluşur. Deyim listeleri s bloğunda(§13.3) ve switch_block'lerde(§13.8.3) yer alır.

statement_list
    : statement+
    ;

Bir ifade listesi, denetimi ilk ifadeye aktararak yürütülür. Denetim bir deyimin bitiş noktasına ulaştığında ve olduğunda, denetim bir sonraki deyime aktarılır. Eğer ve ne zaman kontrol son deyimin bitiş noktasına ulaşırsa, kontrol deyim listesinin bitiş noktasına aktarılır.

Aşağıdakilerden en az biri doğruysa, deyim listesindeki bir deyime ulaşılabilir:

  • İfade, ilk ifadedir ve ifadenin listesinin kendisine ulaşılabilir.
  • Önceki ifadenin bitiş noktasına ulaşılabilir.
  • Deyim, etiketli bir deyimdir ve etikete erişilebilir bir deyim tarafından referans verilir goto.

Listedeki son deyimin bitiş noktasına ulaşılabilirse, deyim listesinin bitiş noktasına ulaşılabilir.

13.4 Boş deyim

bir empty_statement hiçbir şey yapmaz.

empty_statement
    : ';'
    ;

Boş bir deyim, deyiminin gerekli olduğu bir bağlamda gerçekleştirilecek işlem olmadığında kullanılır.

Boş bir deyimin yürütülmesi yalnızca kontrolü deyimin bitiş noktasına aktarır. Bu nedenle, boş bir deyimin bitiş noktasına, boş deyim erişilebilir olduğunda ulaşılabilir.

Örnek: Boş gövdeli bir while deyim yazarken boş bir deyim kullanılabilir:

bool ProcessMessage() {...}
void ProcessMessages()
{
    while (ProcessMessage())
        ;
}

Ayrıca, bir bloğun "}" kapatılmasından hemen önce bir etiket bildirmek için boş bir deyim kullanılabilir:

void F(bool done)
{
    ...
    if (done)
    {
        goto exit;
    }
    ...
  exit:
    ;
}

son örnek

13.5 Etiketli deyimler

Etiketli bir deyim, bir deyimin başına bir etiket eklenmesine izin verir. Etiketli deyimlere bloklar halinde izin verilir, ancak ekli deyimler olarak izin verilmez.

labeled_statement
    : identifier ':' statement
    ;

Etiketlenmiş bir ifade, tanımlayıcı isim olarak bir etiket bildirir. Bir etiketin kapsamı, iç içe yerleştirilmiş bloklar da dahil olmak üzere etiketin bildirildiği bloğun tamamıdır. Aynı ada sahip iki etiketin çakışan kapsamlara sahip olması derleme zamanı hatasıdır.

Etiketin kapsamındaki deyimlerden goto etiketi (§13.10.4) referans olarak kullanılabilir.

Not: Bu, ifadelerin goto blokların içinde ve dışında kontrolü aktarabileceği, ancak hiçbir zaman bloklara aktaramayacağı anlamına gelir. dipnot

Etiketlerin kendi bildirim alanları vardır ve diğer tanımlayıcıları engellemez.

Örnek: Örnek

int F(int x)
{
    if (x >= 0)
    {
        goto x;
    }
    x = -x;
  x:
    return x;
}

geçerlidir ve hem parametre hem de etiket olarak x adını kullanır.

son örnek

Etiketlenmiş bir deyimin yürütülmesi, etiketi izleyen deyimin yürütülmesine tam olarak karşılık gelir.

Normal denetim akışı tarafından sağlanan erişilebilirliğe ek olarak, etiketli bir deyim, erişilebilir bir goto deyimi etikete başvuruda bulunursa erişilebilir olur, ancak bu goto deyimi, bitiş noktası ulaşılamayan bir try bloğu içeren ve etiketli deyimin catch dışında olduğu bir try_statement bloğunun finally bloğu veya bir bloğu içinde değilse.

13.6 Beyan ifadeleri

13.6.1 Genel

declaration_statement bir veya daha fazla yerel değişken, bir veya daha fazla yerel sabit ya da yerel işlev bildirir. Bildirim ifadelerine bloklarda ve switch bloklarında izin verilir, ancak gömülü ifadeler olarak izin verilmez.

declaration_statement
    : local_variable_declaration ';'
    | local_constant_declaration ';'
    | local_function_declaration
    ;

Yerel değişken bir local_variable_declaration (§13.6.2) kullanılarak bildirilir. Yerel sabit, local_constant_declaration (§13.6.3) kullanılarak bildirilir. Yerel bir işlev local_function_declaration (§13.6.4) kullanılarak bildirilir.

Bildirilen adlar en yakın kapsayan bildirim alanına (§7.3) eklenir.

13.6.2 Yerel değişken bildirimleri

13.6.2.1 Genel

bir local_variable_declaration bir veya daha fazla yerel değişken bildirir.

local_variable_declaration
    : implicitly_typed_local_variable_declaration
    | explicitly_typed_local_variable_declaration
    | explicitly_typed_ref_local_variable_declaration
    ;

Örtülü olarak belirlenen bildirimler bağlamsal anahtar kelimeyi (§6.4.4) var içerir ve bu da üç kategori arasında aşağıdaki gibi çözümlenen bir sözdizimsel belirsizliğe neden olur.

  • Kapsam içinde adlı var bir tür yoksa ve giriş implicitly_typed_local_variable_declaration eşleşiyorsa seçilir;
  • Aksi takdirde, var adındaki bir tür kapsam dahilindeyse, implicitly_typed_local_variable_declaration olası bir eşleşme olarak değerlendirilmez.

Bir local_variable_declaration her değişken, sırasıyla örtük olarak yazılan, açıkça yazılan ve başvurulan yerel değişkenler için implicitly_typed_local_variable_declarator, explicitly_typed_local_variable_declarator veya ref_local_variable_declarator biri olan bir bildirimci tarafından sunulur. Bildirimci, tanıtılan değişkenin adını (tanımlayıcı) ve varsa ilk değerini tanımlar.

Bir bildirimde birden çok bildirimci varsa, bunlar soldan sağa doğru (§9.4.4.5) tüm başlatma ifadeleri de dahil olmak üzere işlenir.

Not: local_variable_declaration'ın for_initializer (§13.9.4) veya resource_acquisition (§13.14) olarak geçmediği durumlarda, bu soldan sağa sıra, ayrı bir local_variable_declaration içinde yer alan her bildirimciye eşdeğerdir. Örneğin:

void F()
{
    int x = 1, y, z = x * 2;
}

eşdeğerdir:

void F()
{
    int x = 1;
    int y;
    int z = x * 2;
}

dipnot

Yerel değişkenin değeri bir simple_name (§12.8.4) kullanılarak bir ifadede elde edilir. Değerinin elde edildiği her konuma kesinlikle bir yerel değişken (§9.4) atanmalıdır. Bir local_variable_declaration tarafından sunulan her yerel değişken başlangıçta atanmamış (§9.4.3). Bildirimcinin başlatma ifadesi varsa, tanıtılan yerel değişken bildirimcinin sonunda atanmış olarak sınıflandırılır (§9.4.4.5).

bir local_variable_declaration tarafından tanıtılan yerel değişkenin kapsamı aşağıdaki gibi tanımlanır (§7.7):

  • Bildirim for_initializer olarak gerçekleşirse, kapsam for_initializer, for_condition, for_iterator ve embedded_statement'tır (§13.9.4);
  • Eğer bildirim bir kaynak edinimi olarak gerçekleşirse, kapsam, using_statement (§13.14) ifadesinin semantik açıdan eşdeğer genişlemesinin en dış bloğudur.
  • Aksi takdirde kapsam, bildirimin gerçekleştiği blok olur.

Bir yerel değişkene, ismini bildiren öğenin öncesinde veya bildirici ifadesinin içindeki herhangi bir başlatma ifadesi içinde metinsel bir konumda kullanmak bir hatadır. Yerel değişken kapsamında, aynı ada sahip başka bir yerel değişken, yerel işlev veya sabit bildirmek derleme zamanında hataya yol açar.

Bir ref yerel değişkeninin ref-safe-context (§9.7.2), onu başlatan değişken_referansı'nın ref-safe bağlamıdır. Başvuru (ref) olmayan yerel değişkenlerin güvenli bağlamı bildirim bloğudur.

13.6.2.2 Örtük olarak yazılan yerel değişken bildirimleri

implicitly_typed_local_variable_declaration
    : 'var' implicitly_typed_local_variable_declarator
    | ref_kind 'var' ref_local_variable_declarator
    ;

implicitly_typed_local_variable_declarator
    : identifier '=' expression
    ;

Örtük olarak_tanımlanan_yerel_değişken_tanımı, bir adet yerel değişken olan kimliği tanıtır. İfade veya değişken_atıf derleme zamanı türüne sahip olmalıdır. T İlk alternatif, ifadenin ilk değerine sahip bir değişken bildirir; türü T? null atanamaz bir başvuru türü olduğunda T , aksi takdirde türü şeklindedir T. İkinci alternatif, ilk değeri refvariable_reference olan bir ref değişkeni bildirir; eğer ref T? null atanamaz bir başvuru türüyse, türü T olur, aksi takdirde türü ref T olur. (ref_kind§15.6.1'de açıklanmıştır.)

Örnek:

var i = 5;
var s = "Hello";
var d = 1.0;
var numbers = new int[] {1, 2, 3};
var orders = new Dictionary<int,Order>();
ref var j = ref i;
ref readonly var k = ref i;

Yukarıdaki örtük olarak yazılan yerel değişken bildirimleri, aşağıdaki açıkça yazılan bildirimlere tam olarak eşdeğerdir:

int i = 5;
string s = "Hello";
double d = 1.0;
int[] numbers = new int[] {1, 2, 3};
Dictionary<int,Order> orders = new Dictionary<int,Order>();
ref int j = ref i;
ref readonly int k = ref i;

Aşağıda, örtük olarak yazılan yerel değişken bildirimleri yanlıştır:

var x;                  // Error, no initializer to infer type from
var y = {1, 2, 3};      // Error, array initializer not permitted
var z = null;           // Error, null does not have a type
var u = x => x + 1;     // Error, anonymous functions do not have a type
var v = v++;            // Error, initializer cannot refer to v itself

son örnek

13.6.2.3 Açıkça yazılan yerel değişken bildirimleri

explicitly_typed_local_variable_declaration
    : type explicitly_typed_local_variable_declarators
    ;

explicitly_typed_local_variable_declarators
    : explicitly_typed_local_variable_declarator
      (',' explicitly_typed_local_variable_declarator)*
    ;

explicitly_typed_local_variable_declarator
    : identifier ('=' local_variable_initializer)?
    ;

local_variable_initializer
    : expression
    | array_initializer
    ;

Açıkça belirtilmiş türde bir yerel değişken tanımı, belirtilen türe sahip bir veya birden fazla yerel değişken tanıtır.

Bir local_variable_initializer varsa, türü basit atama (§12.21.2) veya dizi başlatma (§17.7) kurallarına göre uygun olacaktır ve değeri değişkenin ilk değeri olarak atanır.

13.6.2.4 Açıkça yazılan ref yerel değişken bildirimleri

explicitly_typed_ref_local_variable_declaration
    : ref_kind type ref_local_variable_declarators
    ;

ref_local_variable_declarators
    : ref_local_variable_declarator (',' ref_local_variable_declarator)*
    ;

ref_local_variable_declarator
    : identifier '=' 'ref' variable_reference
    ;

Başlatıcı variable_reference tür tür olmalı ve başvuru ataması (§12.21.3) için aynı gereksinimleri karşılamalıdır.

ref_kindref readonly ise, bildirilmekte olan tanımlayıcılar salt okunur olarak ele alınan değişkenlere referanslardır. Aksi takdirde, ref_kindref ise, bildirilen tanımlayıcılar yazılabilir değişkenlere referans olmalıdır.

method_modifier ile bildirilen bir yöntem içinde veya yineleyici içinde (ref struct) bir başv yerel değişkeni veya türündekiasync bir değişkeni bildirmek derleme zamanı hatasıdır.

13.6.3 Yerel sabit bildirimleri

bir local_constant_declaration bir veya daha fazla yerel sabit bildirir.

local_constant_declaration
    : 'const' type constant_declarators
    ;

constant_declarators
    : constant_declarator (',' constant_declarator)*
    ;

constant_declarator
    : identifier '=' constant_expression
    ;

local_constant_declaration'ın türü, bildirim tarafından tanıtılan sabitlerin türünü belirtir. Türün ardından her biri yeni bir sabit ekleyen constant_declaratorlistesi yer alır. constant_declarator, sabiti adlandıran bir tanımlayıcı, ardından "=" belirteci ve ardından sabitin değerini veren bir constant_expression (§12.23) oluşur.

Yerel sabit bildirimin türü ve constant_expression , sabit üye bildiriminin (§15.4) kurallarıyla aynı kurallara uyacaktır.

Yerel sabitin değeri, simple_name (§12.8.4) kullanılarak bir ifadede elde edilir.

Yerel sabitin kapsamı, bildirimin gerçekleştiği blok olur. constant_declarator sonundan önce metinsel bir konumda yerel sabite başvurmak bir hatadır.

Birden çok sabit bildiren yerel sabit bildirimi, aynı türe sahip tek sabitlerin birden çok bildirimine eşdeğerdir.

13.6.4 Yerel işlev bildirimleri

bir local_function_declaration yerel bir işlev bildirir.

local_function_declaration
    : local_function_modifier* return_type local_function_header
      local_function_body
    | ref_local_function_modifier* ref_kind ref_return_type
      local_function_header ref_local_function_body
    ;

local_function_header
    : identifier '(' parameter_list? ')'
    | identifier type_parameter_list '(' parameter_list? ')'
      type_parameter_constraints_clause*
    ;

local_function_modifier
    : ref_local_function_modifier
    | 'async'
    ;

ref_local_function_modifier
    : 'static'
    | unsafe_modifier   // unsafe code support
    ;

local_function_body
    : block
    | '=>' null_conditional_invocation_expression ';'
    | '=>' expression ';'
    ;

ref_local_function_body
    : block
    | '=>' 'ref' variable_reference ';'
    ;

Dil bilgisi notu: Bir local_function_body tanındığında hem null_conditional_invocation_expression hem de ifade alternatifleri geçerliyse, ilki seçilir. (§15.6.1)

Örnek: Yerel işlevler için iki yaygın kullanım örneği vardır: yineleyici yöntemleri ve zaman uyumsuz yöntemler. Yineleyici yöntemlerinde, tüm özel durumlar yalnızca döndürülen sırayı numaralandıran kod çağrılırken gözlemlenir. Zaman uyumsuz yöntemlerde, tüm özel durumlar yalnızca döndürülen Görev beklendiğinde gözlemlenir. Aşağıdaki örnek, yerel bir işlev kullanarak parametre doğrulamasını yineleyici uygulamasından ayırmayı gösterir:

public static IEnumerable<char> AlphabetSubset(char start, char end)
{
    if (start < 'a' || start > 'z')
    {
        throw new ArgumentOutOfRangeException(paramName: nameof(start),
            message: "start must be a letter");
    }
    if (end < 'a' || end > 'z')
    {
        throw new ArgumentOutOfRangeException(paramName: nameof(end),
            message: "end must be a letter");
    }
    if (end <= start)
    {
        throw new ArgumentException(
            $"{nameof(end)} must be greater than {nameof(start)}");
    }
    return AlphabetSubsetImplementation();

    IEnumerable<char> AlphabetSubsetImplementation()
    {
        for (var c = start; c < end; c++)
        {
            yield return c;
        }
    }
}

son örnek

Aşağıda aksi belirtilmedikçe, tüm dil bilgisi öğelerinin semantiği, yöntem yerine yerel işlev bağlamında okunan method_declaration (§15.6.1) ile aynıdır.

Yerel_fonksiyon_bildiriminin tanımlayıcısı, kapsandığı tüm yerel değişken bildirim alanlarını da içeren bildirilen blok kapsamında benzersiz olmalıdır. Bunun bir sonucu olarak, aşırı yüklenmiş local_function_declaration'lere izin verilmemesidir.

local_function_declaration bir async (§15.14) değiştirici ve bir unsafe (§23.1) değiştirici içerebilir. Bildirim async değiştiricisini içeriyorsa dönüş türü void veya bir «TaskType» türü olmalıdır (§15.14.1). Bildirim değiştiriciyi static içeriyorsa işlev statik bir yerel işlevdir; aksi takdirde statik olmayan bir yerel işlevdir. type_parameter_list veya parameter_listöznitelik içermesi derleme zamanı hatasıdır. Yerel işlev güvenli olmayan bir bağlamda (§23.2) bildirilirse, yerel işlev bildirimi değiştiriciyi içermese bile güvenli olmayan kod içerebilir unsafe .

Yerel bir işlev bir blok kapsamında bildirilir. Statik olmayan bir yerel işlev, kapsayan kapsamdan değişkenleri yakalayabilirken, statik bir yerel işlev bu nedenle kapsayan yerel değişkenlere, parametrelere, statik olmayan yerel işlevlere veya this erişimi olmadığı için yakalayamaz. Bir yakalanmış değişken, statik olmayan bir yerel işlevin gövdesi tarafından okunuyorsa ve bu değişkene işleve yapılan her çağrıdan önce kesinlikle bir atama yapılmadıysa, bu derleme zamanı hatası oluşur. Derleyici, dönüşte hangi değişkenlerin kesinlikle atandığını belirler (§9.4.4.33).

Türü this bir yapı türü olduğunda, yerel fonksiyonun gövdesinin this öğesine erişmesi derleme zamanı hatasıdır. Erişimin açık (this.xolduğu gibi) veya örtük (x'nin yapının örnek üyesi olduğu x olduğu gibi) olması durumu değiştirmez. Bu kural yalnızca bu tür bir erişimi yasaklar ve üye aramasının yapının bir üyesiyle sonuçlanıp sonuçlanmadığını etkilemez.

Yerel işlevin gövdesinde, hedefi yerel işlevin gövdesinin dışında olan bir goto deyimi, break deyimi veya continue deyimi bulunması derleme zamanı hatasıdır.

Not: Yukarıdaki kurallar this ve goto, §12.19.3'teki anonim işlevlerin kurallarını yansıtıyor. dipnot

Yerel işlev, bildiriminden önce sözcük temelli bir noktadan çağrılabilir. Ancak, işlevin yerel işlevde kullanılan bir değişkenin (§7.7) bildiriminden önce sözcük temelli olarak bildirilmesi bir derleme zamanı hatasıdır.

Bir yerel işlevin, herhangi bir kapsayıcı yerel değişken bildirim alanında belirtilen adla aynı ada sahip bir parametre, tür parametresi veya yerel değişken bildirmesi derleme zamanı hatasıdır.

Yerel işlev gövdelerine her zaman ulaşılabilir. Yerel işlev bildiriminin başlangıç noktasına ulaşılabilirse, yerel işlev bildiriminin uç noktasına ulaşılabilir.

Örnek: Aşağıdaki örnekte, L başlangıç noktası ulaşılabilir olmasa bile L gövdesine ulaşılabilir. L başlangıç noktasına ulaşılamadığı için L uç noktasını izleyen deyime erişilemez.

class C
{
    int M()
    {
        L();
        return 1;

        // Beginning of L is not reachable
        int L()
        {
            // The body of L is reachable
            return 2;
        }
        // Not reachable, because beginning point of L is not reachable
        return 3;
    }
}

Başka bir deyişle, yerel işlev bildiriminin konumu, içeren işlevdeki deyimlerin erişilebilirliğini etkilemez. son örnek

Eğer yerel işlevin argümanının türü dynamic ise, çağrılacak işlevin derleme zamanında çözümlenmesi zorunludur, çalışma zamanında değil.

Bir ifade ağacında yerel işlev kullanılmamalıdır.

Statik yerel işlev

  • Kapsayan kapsamdan statik üyelere, tür parametrelerine, sabit tanımlara ve statik yerel işlevlere başvurabilir.
  • Örtük bir this başvurusundan veya base ya da this örnek üyelerinden, kapsayan kapsamdan yerel değişkenlere, parametrelere veya statik olmayan yerel işlevlere başvurulmamalıdır. Ancak, ifadede nameof() tüm bunlara izin verilir.

13.7 İfade deyimleri

expression_statement belirli bir ifadeyi değerlendirir. İfade ile hesaplanan değer (varsa) atılır.

expression_statement
    : statement_expression ';'
    ;

statement_expression
    : null_conditional_invocation_expression
    | invocation_expression
    | object_creation_expression
    | assignment
    | post_increment_expression
    | post_decrement_expression
    | pre_increment_expression
    | pre_decrement_expression
    | await_expression
    ;

İfadelerin tümüne deyim olarak izin verilmez.

Not: Özellikle, yalnızca bir değeri hesaplayan (atılacak) ve x + y gibi ifadelere, deyim olarak izin verilmez. dipnot

bir expression_statement yürütülmesi, kapsanan ifadeyi değerlendirir ve ardından denetimi expression_statement bitiş noktasına aktarır. Bir expression_statement bitiş noktasına ulaşılabilir, eğer expression_statement ulaşılabilir ise.

13.8 Seçim ifadeleri

13.8.1 Genel

Seçim deyimleri, bazı ifadelerin değerine göre yürütme için bir dizi olası deyimden birini seçer.

selection_statement
    : if_statement
    | switch_statement
    ;

13.8.2 If deyimi

deyimi, if Boole ifadesinin değerine göre yürütme için bir deyim seçer.

if_statement
    : 'if' '(' boolean_expression ')' embedded_statement
    | 'if' '(' boolean_expression ')' embedded_statement
      'else' embedded_statement
    ;

Bir else parçası, sözdiziminin izin verdiği sözcüksel olarak en yakın if ile bağlanır.

Örnek: Bu nedenle formun bir if deyimi

if (x) if (y) F(); else G();

ile eşdeğer

if (x)
{
    if (y)
    {
        F();
    }
    else
    {
        G();
    }
}

son örnek

Bir if ifadesi şu şekilde yürütülür:

  • boolean_expression (§12.24) değerlendirilir.
  • Boole ifadesi değerini verirse true, denetim ilk katıştırılmış deyime aktarılır. Denetim bu deyimin bitiş noktasına ulaştığında ve olduğunda, denetim deyiminin if bitiş noktasına aktarılır.
  • Boole ifadesi ortaya false çıkarsa ve bir else parça varsa, denetim ikinci katıştırılmış deyime aktarılır. Denetim bu deyimin bitiş noktasına ulaştığında ve olduğunda, denetim deyiminin if bitiş noktasına aktarılır.
  • Boole ifadesi false sonucunu verirse ve bir else kısım yoksa, denetim if deyiminin bitiş noktasına aktarılır.

Bir if deyiminin ilk eklenmiş deyimine ulaşılabilir, eğer if deyimi ulaşılabilirse ve Boole ifadesi sabit bir değere falsesahip değilse.

Eğer mevcutsa, bir if deyiminin ikinci katıştırılmış deyimi, if deyimi erişilebilir durumda olduğu ve Boole ifadesi true sabit değerine sahip olmadığı takdirde erişilebilir.

Eğer gömülü deyimlerinden en az birinin bitiş noktasına ulaşılabiliyorsa, bir if deyiminin bitiş noktasına da ulaşılabilir. Ek olarak, bir if deyiminin else parçası yoksa ve if deyimine ulaşılabiliyorsa, Boole ifadesinin sabit değeri true değilse, bu deyimin bitiş noktasına da ulaşılabilir.

13.8.3 Switch ifadesi

switch deyimi, switch ifadesinin değerine karşılık gelen ilgili anahtar etiketine sahip bir deyim listesini yürütmek üzere seçer.

switch_statement
    : 'switch' '(' expression ')' switch_block
    ;

switch_block
    : '{' switch_section* '}'
    ;

switch_section
    : switch_label+ statement_list
    ;

switch_label
    : 'case' pattern case_guard?  ':'
    | 'default' ':'
    ;

case_guard
    : 'when' expression
    ;

switch_statement, anahtar sözcüğünden switchve ardından parantezli ifadeden (anahtar ifadesi olarak adlandırılır) ve ardından bir switch_block oluşur. switch_block, küme parantez içine alınmış sıfır veya daha fazla switch_section oluşur. Her switch_section bir veya daha fazla switch_label ve ardından bir statement_list (§13.3.2) oluşur. Değeri test edilen her switch_label içeren case, switch ifadesinin karşılaştırıldığı ilişkili bir desene (§11) sahiptir. case_guard varsa, ifadesi örtük olarak türüne bool dönüştürülebilir olmalıdır ve bu ifade, vakanın karşılanmış sayılması için ek bir koşul olarak değerlendirilir.

Deyimin switch ifadesi tarafından oluşturulur.

  • Switch ifadesinin türü sbyte, byte, short, ushort, int, uint, long, ulong, char, bool, string veya bir enum_type ise veya bu türlerden birine karşılık gelen null atanabilir değer türüyse, bu deyimin yöneten türdür switch.
  • Aksi takdirde, anahtar ifadelerinin türünden aşağıdaki olası yönetim türlerinden birine yönelik tam olarak bir kullanıcı tanımlı örtük dönüştürme varsa: sbyte, byte, short, ushort, int, uint, long, ulong, char, string veya bu türlerden birine karşılık gelen null atanabilir bir değer türü varsa, dönüştürülen tür, switch ifadesinin yönetim türüdür.
  • Aksi takdirde, switch deyiminin yönlendiren türü, switch ifadesinin türüdür. Böyle bir tür yoksa bu bir hatadır.

Bir default ifadesinde en fazla bir switch etiket olabilir.

Eğer herhangi bir anahtar etiketinin deseni, giriş ifadesinin türüne uygulanamazsa (§11.2.1), bu bir hatadır.

Anahtar deyimindeki herhangi bir anahtar etiketinin deseni, büyük/küçük harf koruyucusu olmayan veya büyük/küçük harf koruyucusu değeri true olan sabit bir ifade içeren, önceki anahtar etiketlerinin desenleri kümesi (§11.3) tarafından altında toplanırsa bir hatadır.

Örnek:

switch (shape)
{
    case var x:
        break;
    case var _: // error: pattern subsumed, as previous case always matches
        break;
    default:
        break;  // warning: unreachable, all possible values already handled.
}

son örnek

Bir switch ifadesi aşağıdaki gibi yürütülür:

  • Switch ifadesi değerlendirilir ve yöneten türe dönüştürülür.
  • Denetim, dönüştürülen anahtar ifadesinin değerine göre aktarılır:
    • Anahtar ifadesinin case değeriyle eşleşen ve koruma ifadesinin eksik olduğu veya true olarak değerlendirildiği aynı switch ifadedeki etiket kümesinin ilk deseni, denetimin eşleşen case etiketi izleyen ifade listesine aktarılmasına neden olur.
    • Aksi takdirde, bir default etiketi varsa, kontrol default etiketinin ardından gelen deyim listesine aktarılır.
    • Aksi takdirde, kontrol switch ifadesinin bitiş noktasına aktarılır.

Not: Çalışma zamanında desenlerin eşleşme sırası tanımlanmamıştır. Derleyicinin desenleri sıra dışı eşleştirmesine ve diğer desenlerin eşleşmesinin sonucunu hesaplamak için zaten eşleşen desenlerin sonuçlarını yeniden kullanmasına izin verilir (ancak gerekli değildir). Bununla birlikte, ifadeyle eşleşen ve guard yan tümcesinin eksik olduğu veya trueolarak değerlendirildiği sözcük temelli ilk deseni belirlemek için bir derleyici gereklidir. dipnot

Switch bölümünün deyim listesinin bitiş noktasına ulaşılabiliyorsa, derleme zamanı hatası oluşur. Bu, "düşme yok" kuralı olarak bilinir.

Örnek: Örnek

switch (i)
{
    case 0:
        CaseZero();
        break;
    case 1:
        CaseOne();
        break;
    default:
        CaseOthers();
        break;
}

geçerli çünkü hiçbir geçiş bölümünün ulaşılabilir bir uç noktası yok. C ve C++'ın aksine, bir switch bölümünün yürütülmesinden sonra bir sonraki switch bölümüne "geçilmesine" izin verilmez ve örnek

switch (i)
{
    case 0:
        CaseZero();
    case 1:
        CaseZeroOrOne();
    default:
        CaseAny();
}

Bu, derleme zamanı hatasıyla sonuçlanır. Bir anahtar bölümünün yürütülmesini başka bir anahtar bölümünün yürütülmesi izleyecekse, açıkça bir goto case veya goto default deyimi kullanılmalıdır:

switch (i)
{
    case 0:
        CaseZero();
        goto case 1;
    case 1:
        CaseZeroOrOne();
        goto default;
    default:
        CaseAny();
        break;
}

son örnek

Bir switch_section içinde birden fazla etiket kullanılabilir.

Örnek: Örnek

switch (i)
{
    case 0:
        CaseZero();
        break;
    case 1:
        CaseOne();
        break;
    case 2:
    default:
        CaseTwo();
        break;
}

geçerli. Etiketler case 2: ve default: aynı switch_section parçası olduğundan, örnek "geçilmez" kuralını ihlal etmez.

son örnek

Not: "Geçiş yok" kuralı, ifadelere yanlışlıkla yer verilmediğinde C ve C++ dillerinde sık rastlanan bir hata türünü önler. Örneğin, yukarıdaki deyimin switch bölümleri, deyiminin davranışını etkilemeden tersine çevrilebilir:

switch (i)
{
    default:
        CaseAny();
        break;
    case 1:
        CaseZeroOrOne();
        goto default;
    case 0:
        CaseZero();
        goto case 1;
}

dipnot

Not: Switch bölümünün deyim listesi genellikle bir break, goto caseveya goto default deyimiyle biter, ancak deyim listesinin bitiş noktasını erişilemez hale getiren herhangi bir yapıya izin verilir. Örneğin, Boole ifadesi tarafından denetlenen bir while deyiminin true hiçbir zaman bitiş noktasına ulaşmadığı bilinmektedir. Benzer şekilde, bir throw veya return deyimi denetimi her zaman başka bir yere aktarır ve hiçbir zaman bitiş noktasına ulaşmaz. Bu nedenle, aşağıdaki örnek geçerlidir:

switch (i)
{
     case 0:
         while (true)
         {
             F();
         }
     case 1:
         throw new ArgumentException();
     case 2:
         return;
}

dipnot

Örnek: Deyimin switch idare türü türü stringolabilir. Örneğin:

void DoCommand(string command)
{
    switch (command.ToLower())
    {
        case "run":
            DoRun();
            break;
        case "save":
            DoSave();
            break;
        case "quit":
            DoQuit();
            break;
        default:
            InvalidCommand(command);
            break;
    }
}

son örnek

Not: Dize eşitliği işleçleri (§12.12.8) gibi, switch deyimi de büyük/küçük harf duyarlıdır ve anahtar ifadesi dizesi bir etiket sabitiyle tam olarak eşleştiğinde belirli bir case durum bölümünü yürütür. son not Bir switch deyiminin idare türü veya null atanabilir bir değer türü olduğunda string , değere null etiket sabiti case olarak izin verilir.

Bir switch_block'un statement_list'i bildirim deyimleri (§13.6) içerebilir. Yerel değişkenin veya anahtar bloğunda bildirilen sabitin kapsamı anahtar bloğudur.

Aşağıdakilerden en az biri doğruysa anahtar etiketine ulaşılabilir:

  • Switch ifadesi sabit bir değerdir ve
    • etiket, deseninin bu değerle case (§11.2.1) bir 'dir ve etiketin koruyucusu ya mevcut değildir ya da değeri false olan sabit bir ifade değildir; veya
    • bu bir default etikettir ve hiçbir anahtar bölümü, deseni bu değerle eşleşebilecek, koruyucusu ya eksik olan ya da true değerine sahip bir sabit ifade içeren bir durum etiketi içermez.
  • Switch ifadesi sabit bir değer değildir ve
    • etiket, case değeri false sabiti olmayan, korumasız veya koruyucusu olmayan bir etikettir; veya
    • bu bir default etikettir ve
      • değeri sürekli true olan bir korumaya sahip olan veya olmayan, switch deyiminin durumları arasında görünen desen kümesi, switch yöneten tür için kapsamlı değildir (§11.4); veya
      • Anahtar kontrol türü, null atanabilir bir türdür ve koruması olmayan veya değeri true sabiti olan korumalara sahip switch deyiminin durumları arasında görünen desen kümesi, null ile eşleşecek bir desen içermez.
  • Anahtar etiketi, erişilebilir bir goto case veya goto default deyimi tarafından referans alınır.

Belirli bir switch bölümünün deyim listesi erişilebilir durumdaysa switch deyimi erişilebilir olmalı ve switch bölümü erişilebilir bir switch etiketi içermelidir.

Eğer switch deyimine ulaşılabiliyorsa ve aşağıdakilerden en az biri doğruysa, bir switch deyiminin bitiş noktasına ulaşılabilir.

  • switch deyiminin içinde, break deyiminden çıkan erişilebilir bir switch deyimi vardır.
  • Ya hiç default etiketi yok veya
    • Anahtar ifadesi sabit olmayan bir değerdir ve değeri sabit true olan korumalar içermeyen veya bu tür korumalar barındıran switch deyimi durumları arasında yer alan desenlerin kümesi, anahtar kontrol türü için kapsamlı değildir (§11.4).
    • Switch ifadesi, null atanabilir bir türün sabit olmayan bir değerdir ve true sabitine sahip korumalar veya korumaları olmayan switch ifadesi durumlarının hiçbirinde herhangi bir desen null ile uyuşmaz.
    • Switch ifadesi sabit bir değerdir ve korumasız veya koruyucusu true sabiti olan hiçbir case etiket bu değerle eşleşmez.

Örnek: Aşağıdaki kod, yan tümcesinin when kısa bir kullanımını gösterir:

static object CreateShape(string shapeDescription)
{
   switch (shapeDescription)
   {
        case "circle":
            return new Circle(2);
        …
        case var o when string.IsNullOrWhiteSpace(o):
            return null;
        default:
            return "invalid shape description";
    }
}

Var durumu, null, boş dize veya yalnızca boşluk içeren herhangi bir dizeyle eşleşir. son örnek

13.9 Yineleme ifadeleri

13.9.1 Genel

Yineleme deyimleri, katıştırılmış bir deyimi tekrar tekrar yürütür.

iteration_statement
    : while_statement
    | do_statement
    | for_statement
    | foreach_statement
    ;

13.9.2 While deyimi

while deyimi, gömülü bir deyimi koşullu olarak sıfır veya daha fazla kez yürütür.

while_statement
    : 'while' '(' boolean_expression ')' embedded_statement
    ;

Bir while ifadesi aşağıdaki gibi yürütülür:

  • boolean_expression (§12.24) değerlendirilir.
  • Boole ifadesi true sonuç verirse, kontrol gömülü deyime aktarılır. Denetim, ekli deyimin bitiş noktasına ulaştığında ve eğer bu bir continue deyiminin yürütülmesinden kaynaklanıyorsa, denetim while deyiminin başına aktarılır.
  • Boole ifadesi değerini verirse false, denetim deyiminin while bitiş noktasına aktarılır.

Bir while deyiminin katıştırılmış deyiminde, denetimi deyimin bitiş noktasına break aktarmak için bir deyim (while) kullanılabilir (böylece eklenmiş deyimin yinelenmesi sona erer) ve denetimi katıştırılmış deyimin bitiş noktasına aktarmak için bir continue deyim (§13.10.3) kullanılabilir (böylece deyimin başka bir yinelemesini while gerçekleştirir).

Bir while deyiminin katıştırılmış deyimine ulaşılabilir, eğer while deyimi ulaşılabilirse ve Boole ifadesi sabit bir değere false sahip değilse.

Aşağıdakilerden en az biri doğruysa deyiminin while bitiş noktasına ulaşılabilir:

  • while deyiminin içinde, break deyiminden çıkan erişilebilir bir while deyimi vardır.
  • while deyimine ulaşılabilir ve Boole ifadesi sabit değerine truesahip değil.

13.9.3 Do deyimi

do deyimi, gömülü bir ifadeyi bir veya daha fazla kez koşullu olarak yürütür.

do_statement
    : 'do' embedded_statement 'while' '(' boolean_expression ')' ';'
    ;

Bir do ifadesi aşağıdaki gibi yürütülür:

  • Kontrol, gömülü deyime aktarılır.
  • Denetim katıştırılmış deyimin bitiş noktasına ulaştığında (büyük olasılıkla bir continue deyimin yürütülmesinden), boolean_expression (§12.24) değerlendirilir. Boolean ifadesinin sonucu true ise, denetim do deyiminin başına aktarılır. Aksi takdirde, kontrol do ifadesinin bitiş noktasına aktarılır.

Bir do deyiminin katıştırılmış deyiminde, denetimi deyimin bitiş noktasına break aktarmak için bir deyim (do) kullanılabilir (böylece eklenmiş deyimin yinelenmesi sona erer) ve denetimi katıştırılmış deyimin bitiş noktasına aktarmak için bir continue deyim (§13.10.3) kullanılabilir (böylece deyimin başka bir yinelemesini do gerçekleştirir).

Bir do deyimine ulaşılabiliyorsa, bir do deyiminin gömülü deyimine de ulaşılabilir.

Aşağıdakilerden en az biri doğruysa deyiminin do bitiş noktasına ulaşılabilir:

  • do deyiminin içinde, break deyiminden çıkan erişilebilir bir do deyimi vardır.
  • Katıştırılmış deyiminin bitiş noktasına ulaşılabilir ve Boole ifadesi sabit değerine truesahip değildir.

13.9.4 For deyimi

for deyimi, bir başlatma ifadeleri dizisini değerlendirir ve ardından, bir koşul doğru olduğunda, katıştırılmış bir deyimi tekrar tekrar yürütür ve bir yineleme ifadeleri dizisini değerlendirir.

for_statement
    : 'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')'
      embedded_statement
    ;

for_initializer
    : local_variable_declaration
    | statement_expression_list
    ;

for_condition
    : boolean_expression
    ;

for_iterator
    : statement_expression_list
    ;

statement_expression_list
    : statement_expression (',' statement_expression)*
    ;

Varsa for_initializer bir local_variable_declaration (§13.6.2) veya virgülle ayrılmış statement_expression(§13.7) listesinden oluşur. Bir for_initializer tarafından bildirilen yerel değişkenin kapsamı for_initializer, for_condition, for_iterator ve embedded_statement içerir.

for_condition mevcutsa, bir boolean_expression (§12.24) olacaktır.

varsa, for_iterator virgülle ayrılmış bir statement_expression(§13.7) listesinden oluşur.

Bir for ifadesi aşağıdaki gibi yürütülür:

  • Bir for_initializer varsa, değişken başlatıcıları veya deyim ifadeleri yazıldıkları sırayla yürütülür. Bu adım yalnızca bir kez gerçekleştirilir.
  • For_condition varsa değerlendirilir.
  • for_condition bulunmuyorsa veya değerlendirme true'i döndürürse, denetim gömülü deyime aktarılır. Denetim katıştırılmış deyimin bitiş noktasına ulaştığında (büyük olasılıkla bir continue deyimin yürütülmesinden), varsa for_iterator ifadeleri sırayla değerlendirilir ve yukarıdaki adımda for_condition değerlendirilmesinden başlayarak başka bir yineleme gerçekleştirilir.
  • for_condition varsa ve değerlendirme sonuç verirsefalse, denetim deyiminin for bitiş noktasına aktarılır.

Bir for deyiminin katıştırılmış deyiminde, denetimi break deyiminin bitiş noktasına aktarmak için bir deyimi (for) kullanılabilir (böylece katıştırılan deyimin yinelenmesini sonlandırır) ve denetimi ekli deyimin bitiş noktasına aktarmak için bir continue deyimi (§13.10.3) kullanılabilir (böylece for_iterator'ü çalıştırır ve for ile başlayarak deyiminin başka bir yinelemesini gerçekleştirir).

for deyiminin gömülü deyimine, aşağıdakilerden biri doğruysa erişilebilir:

  • İfade for ulaşılabilir ancak for_condition mevcut değil.
  • for deyimine ulaşılabilir ve bir for_condition bulunmaktadır ve sabit bir değere sahip değildir.

Aşağıdakilerden en az biri doğruysa deyiminin for bitiş noktasına ulaşılabilir:

  • for deyiminin içinde, break deyiminden çıkan erişilebilir bir for deyimi vardır.
  • for deyimine ulaşılabilir ve bir for_condition bulunmaktadır ve sabit bir değere sahip değildir.

13.9.5 Foreach deyimi

13.9.5.1 Genel

foreach deyimi bir koleksiyonun öğelerini numaralandırır ve koleksiyonun her öğesi için gömülü bir deyimi çalıştırır.

foreach_statement
    : 'await'? 'foreach' '(' ref_kind? local_variable_type identifier
      'in' expression ')' embedded_statement
    ;

Foreach deyiminin local_variable_type ve tanımlayıcısı deyiminin yineleme değişkenini bildirir. var Tanımlayıcı local_variable_type olarak verilirse ve adlandırılmış var bir tür kapsam içinde değilse, yineleme değişkeninin örtük olarak yazılan bir yineleme değişkeni olduğu söylenir ve türü aşağıda belirtildiği gibi deyimin foreach öğe türü olarak alınır.

Hem await hem de ref_kind bir foreach statement içinde mevcut olduğunda bir derleme zamanı hatasıdır.

foreach_statement hem ref hem de readonly'yi ya da hiçbirini içeriyorsa, yineleme değişkeni salt okunur olarak kabul edilir. Aksi takdirde, foreach_statementref içerip readonly olmadan ise, yineleme değişkeni yazılabilir bir değişkeni belirtir.

Yineleme değişkeni, gömülü deyimi kapsayan bir kapsama sahip yerel bir değişkene karşılık gelir. Bir foreach deyiminin yürütülmesi sırasında yineleme değişkeni, yinelemenin şu anda gerçekleştirilmekte olduğu koleksiyon öğesini temsil eder. Yineleme değişkeni salt okunur bir değişkeni belirtirse, katıştırılmış deyimin bunu değiştirmeye (atma veya ++ ve -- işleçleri aracılığıyla) ya da bunu başvuru veya çıkış parametresi olarak geçirmeye çalışması durumunda derleme zamanı hatası oluşur.

Bir foreach deyiminin derleme zamanı işlemesi önce ifadenin koleksiyon türünü, numaralandırıcı türünü ve yineleme türünü belirler. Bir foreach deyiminin işlenmesi §13.9.5.2'de ve bir await foreach deyimi için işleme süreci §13.9.5.3'te ayrıntılı olarak açıklanmıştır.

Not: İfadenull değerine sahipse, çalışma zamanında bir System.NullReferenceException fırlatılır. dipnot

Bir uygulamanın belirli bir foreach_statement farklı şekilde uygulamasına izin verilir; örneğin, performans nedenleriyle, davranış yukarıdaki genişletmeyle tutarlı olduğu sürece.

13.9.5.2 Zaman uyumlu foreach

Bir foreach deyiminin derleme zamanı işlemesi önce ifadenin koleksiyon türünü, numaralandırıcı türünü ve yineleme türünü belirler. Bu belirleme aşağıdaki gibi devam eder:

  • Eğer X türü bir dizi türüyse, X'ten arabirimine örtük bir başvuru dönüşümü vardır (çünkü IEnumerable bu arabirimi uygular). Koleksiyon türü arabirim, IEnumerable numaralandırıcı türü IEnumerator arabirim ve yineleme türü ise dizi türünün öğe türüdür X.
  • Eğer X türü dynamic ise, o zaman ifadesi’den IEnumerable arabirimine (§10.2.10) örtük bir dönüştürme vardır. Koleksiyon türü IEnumerable arabirimi, numaralandırıcı türü ise IEnumerator arabirimidir. var Tanımlayıcı local_variable_type olarak verilirse yineleme türü olurdynamic, aksi takdirde olurobject.
  • Aksi takdirde, tür X'ın uygun bir GetEnumerator metodu olup olmadığını belirleyin.
    • Tür X üzerinde, GetEnumerator tanımlayıcısıyla ve tür bağımsız değişkeni olmadan üye araması gerçekleştirin. Üye araması bir eşleşme üretmiyorsa veya bir belirsizlik veya yöntem grubu olmayan bir eşleşme üretirse, aşağıda açıklandığı gibi numaralandırılabilir bir arabirim olup olmadığını denetleyin. Üye arama bir yöntem grubu dışında bir şey üretirse veya eşleşme yoksa bir uyarı verilmesi önerilir.
    • Elde edilen yöntem grubunu ve boş bir bağımsız değişken listesini kullanarak aşırı yükleme çözümlemesi gerçekleştirin. Aşırı yükleme çözümlemesi geçerli bir yöntemle sonuçlanmıyorsa, belirsizlikle sonuçlanıyorsa veya tek bir en iyi yöntemle sonuçlanıyorsa ancak bu yöntem statikse veya genel değilse, aşağıda açıklandığı gibi numaralandırılabilir bir arabirim olup olmadığını denetleyin. Aşırı yükleme çözümlemesi belirsiz bir genel örnek yöntemi dışında bir şey üretirse veya geçerli yöntem yoksa bir uyarı verilmesi önerilir.
    • E yönteminin dönüş türü GetEnumerator bir sınıf, yapı veya arabirim türü değilse, bir hata oluşturulur ve başka adım atılmaz.
    • Üye arama, E üzerinde, tanımlayıcı Current kullanılarak ve tür bağımsız değişkeni olmaksızın gerçekleştirilir. Üye araması eşleşme sağlamazsa veya sonuç, okumaya izin veren bir genel örnek özelliği dışında bir şeyse, bir hata oluşturulur ve başka bir adım atılmaz.
    • Üye arama, E üzerinde, tanımlayıcı MoveNext kullanılarak ve tür bağımsız değişkeni olmaksızın gerçekleştirilir. Üye araması eşleşme üretmezse veya sonuç bir yöntem grubu dışında herhangi bir şey olursa, bir hata üretilir ve başka adım atılmaz.
    • Aşırı yükleme çözümlemesi, yöntem grubunda boş bir bağımsız değişken listesiyle gerçekleştirilir. Aşırı yükleme çözümlemesi geçerli bir yöntemle sonuçlanmazsa, belirsizlikle sonuçlanırsa veya tek bir en iyi yöntemle sonuçlanırsa, ancak bu yöntem statikse veya genel değilse ya da dönüş türü değilse bool, bir hata oluşturulur ve başka bir adım atılmaz.
    • Koleksiyon türü X, numaralandırıcı türü Eve yineleme türü Current özelliğinin türüdür. Current özelliği değiştiriciyi ref içerebilir; bu durumda döndürülen ifade isteğe bağlı olarak salt okunur olan bir variable_reference (§9.5) olur.
  • Aksi takdirde, numaralandırılabilir bir arabirim olup olmadığını denetleyin:
    • Tᵢ için X'den örtük dönüştürmenin olduğu tüm IEnumerable<Tᵢ> türleri arasında, TT olmadığı ve diğer tüm dynamic türleri için Tᵢ'den IEnumerable<T>'e örtük bir dönüştürme olduğu benzersiz bir tür IEnumerable<Tᵢ> varsa, koleksiyon türü arabirimi IEnumerable<T>, numaralandırıcı türü arabirimi IEnumerator<T> ve yineleme türü T olur.
    • Aksi takdirde, Tbirden fazla tür varsa bir hata üretilir ve başka bir adım atılmaz.
    • Aksi takdirde, X'dan System.Collections.IEnumerable arabirimine örtük bir dönüştürme varsa, koleksiyon türü bu arabirimdir, numaralandırıcı türü System.Collections.IEnumerator arabirimidir ve yineleme türü object olur.
    • Aksi takdirde bir hata oluşturulur ve başka bir adım atılmaz.

Yukarıdaki adımlar başarılı olursa, bir koleksiyon türü C, numaralandırıcı türü E ve yineleme türü T, ref T veya ref readonly T oluşturur. foreach biçiminde bir ifade

foreach (V v in x) «embedded_statement»

daha sonra şu değerle eşdeğerdir:

{
    E e = ((C)(x)).GetEnumerator();
    try
    {
        while (e.MoveNext())
        {
            V v = (V)(T)e.Current;
            «embedded_statement»
        }
    }
    finally
    {
        ... // Dispose e
    }
}

Değişken e , ifade x veya ekli deyim ya da programın başka bir kaynak kodu için görünür veya erişilebilir değildir. Değişken v, gömülü deyimde salt okunurdur. (yineleme türü) ile T arasında, V deyimindeki local_variable_type için açık bir dönüştürme (foreach) yoksa, bir hata üretilir ve başka bir adım atılmaz.

Yineleme değişkeni bir başvuru değişkeni olduğunda (§9.7), formun bir foreach deyimi

foreach (ref V v in x) «embedded_statement»

daha sonra şu değerle eşdeğerdir:

{
    E e = ((C)(x)).GetEnumerator();
    try
    {
        while (e.MoveNext())
        {
            ref V v = ref e.Current;
            «embedded_statement»
        }
    }
    finally
    {
        ... // Dispose e
    }
}

Değişken e , ifade x veya ekli deyim ya da programın başka bir kaynak kodu için görünür veya erişilebilir değildir. Referans değişkeni v gömülü deyimde okuma-yazma iznine sahiptir, ancak v yeniden ref ataması yapılmamalıdır (§12.21.3). Eğer (yineleme türü) ile T (cümledeki V olan ) arasında bir kimlik dönüştürmesi (foreach) yoksa bir hata oluşturulur ve başka adım atılmaz.

foreach ifadesi foreach (ref readonly V v in x) «embedded_statement» şeklinde benzer bir karşılık forma sahiptir, ancak başvuru değişkeni katıştırılmış ifadede v olarak ref readonly bulunduğundan, yeniden atanamaz veya başka bir referans atanamaz.

Döngünün v içine yerleştirilmesi, while içinde bulunan herhangi bir anonim işlev tarafından nasıl yakalandığı (§12.19.6.2) için önemlidir.

Örnek:

int[] values = { 7, 9, 13 };
Action f = null;
foreach (var value in values)
{
    if (f == null)
    {
        f = () => Console.WriteLine("First value: " + value);
    }
}
f();

Genişletilmiş formda v döngü dışında bildirilirse, tüm yinelemeler arasında paylaşılır ve while döngüsünden sonraki değeri, yani son değer, olur. Bu, for çağrısının yazdıracağı 13 değeridir. Bunun yerine, her yinelemenin kendi değişkeni v olduğundan, ilk yinelemede f tarafından yakalanan değer, yazdırılacak olan değeri 7 tutmaya devam eder. (Önceki C# sürümlerinde v ifadesinin while döngüsü dışında bildirildiğine dikkat edin.)

son örnek

finally bloğunun gövdesi aşağıdaki adımlara göre oluşturulur:

  • Eğer E'den System.IDisposable arabirimine örtük bir dönüştürme varsa,

    • E null olamaz bir değer türüyse finally yan tümcesi şu anlamsal eşdeğerine genişletilir:

      finally
      {
          ((System.IDisposable)e).Dispose();
      }
      
    • Aksi takdirde, finally tümcesi aşağıdaki anlamsal eşdeğer hale genişletilir:

      finally
      {
          System.IDisposable d = e as System.IDisposable;
          if (d != null)
          {
              d.Dispose();
          }
      }
      

      E bir değer türü veya bir değer türüne örnekli bir tür parametresiyse, e'in System.IDisposable'ye dönüştürülmesi kutulamanın oluşmasına neden olmaz.

  • Aksi takdirde, korumalı bir türse E yan finally tümcesi boş bir bloğa genişletilir:

    finally {}
    
  • Aksi takdirde, finally yan tümcesi şu şekilde genişletilir:

    finally
    {
        System.IDisposable d = e as System.IDisposable;
        if (d != null)
        {
            d.Dispose();
        }
    }
    

Yerel değişken d herhangi bir kullanıcı kodu için görünür veya erişilebilir değildir. Özellikle, kapsamı finally bloğunu içeren başka bir değişkenle çatışmaz.

Dizinin öğelerinin geçiş sırası foreach aşağıdaki gibidir: Tek boyutlu diziler için öğeleri dizin 0'dan başlayıp dizinle Length – 1biten dizin sırası artan şekilde geçirilir. Çok boyutlu diziler için, öğeler en sağdaki boyutun dizinleri önce artırılır, sonra bir sonraki sol boyut vb. sola doğru geçirilir.

Örnek: Aşağıdaki örnek, iki boyutlu dizideki her değeri öğe sırasına göre yazdırır:

class Test
{
    static void Main()
    {
        double[,] values =
        {
            {1.2, 2.3, 3.4, 4.5},
            {5.6, 6.7, 7.8, 8.9}
        };
        foreach (double elementValue in values)
        {
            Console.Write($"{elementValue} ");
        }
        Console.WriteLine();
    }
}

Üretilen çıkış aşağıdaki gibidir:

1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9

son örnek

Örnek: Aşağıdaki örnekte

int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers)
{
    Console.WriteLine(n);
}

n türünün, int olduğu, numbers'nın yineleme türü olarak tahmin edilir.

son örnek

13.9.5.3 foreach bekleniyor

Bir foreach deyiminin derleme zamanı işlemesi önce ifadenin koleksiyon türünü, numaralandırıcı türünü ve yineleme türünü belirler. Bir foreach deyiminin işlenmesi §13.9.5.2'de ve bir await foreach deyimi için işleme süreci §13.9.5.3'te ayrıntılı olarak açıklanmıştır.

Bu belirleme aşağıdaki gibi devam eder:

  • Türün X uygun GetAsyncEnumerator bir yöntemi olup olmadığını belirleyin:
    • Tür X üzerinde, GetAsyncEnumerator tanımlayıcısıyla ve tür bağımsız değişkeni olmadan üye araması gerçekleştirin. Üye araması bir eşleşme üretmiyorsa veya bir belirsizlik veya yöntem grubu olmayan bir eşleşme üretirse, aşağıda açıklandığı gibi numaralandırılabilir bir arabirim olup olmadığını denetleyin. Üye arama bir yöntem grubu dışında bir şey üretirse veya eşleşme yoksa bir uyarı verilmesi önerilir.
    • Elde edilen yöntem grubunu ve boş bir bağımsız değişken listesini kullanarak aşırı yükleme çözümlemesi gerçekleştirin. Aşırı yükleme çözümlemesi geçerli bir yöntemle sonuçlanmıyorsa, belirsizlikle sonuçlanıyorsa veya tek bir en iyi yöntemle sonuçlanıyorsa ancak bu yöntem statikse veya genel değilse, aşağıda açıklandığı gibi numaralandırılabilir bir arabirim olup olmadığını denetleyin. Aşırı yükleme çözümlemesi belirsiz bir genel örnek yöntemi dışında bir şey üretirse veya geçerli yöntem yoksa bir uyarı verilmesi önerilir.
    • E yönteminin dönüş türü GetAsyncEnumerator bir sınıf, yapı veya arabirim türü değilse, bir hata oluşturulur ve başka adım atılmaz.
    • Üye arama, E üzerinde, tanımlayıcı Current kullanılarak ve tür bağımsız değişkeni olmaksızın gerçekleştirilir. Üye araması eşleşme sağlamazsa veya sonuç, okumaya izin veren bir genel örnek özelliği dışında bir şeyse, bir hata oluşturulur ve başka bir adım atılmaz.
    • Üye arama, E üzerinde, tanımlayıcı MoveNextAsync kullanılarak ve tür bağımsız değişkeni olmaksızın gerçekleştirilir. Üye araması eşleşme üretmezse veya sonuç bir yöntem grubu dışında herhangi bir şey olursa, bir hata üretilir ve başka adım atılmaz.
    • Aşırı yükleme çözümlemesi, yöntem grubunda boş bir bağımsız değişken listesiyle gerçekleştirilir. Aşırı yükleme çözümlemesi geçerli bir yöntemle sonuçlanmazsa, belirsizlikle sonuçlanırsa veya tek bir en iyi yöntemle sonuçlanırsa, ancak bu yöntem statiktir veya genel değildir ya da await_expression (§12.9.8.3) olarak bool sınıflandırıldığı dönüş türü beklenemez (§12.9.8.2), bir hata oluşturulur ve başka bir adım atılmaz.
    • Koleksiyon türü X, numaralandırıcı türü Eve yineleme türü Current özelliğinin türüdür.
  • Aksi takdirde, zaman uyumsuz bir numaralandırılabilir arabirim olup olmadığını denetleyin.
    • Tᵢ için X'den örtük dönüştürmenin olduğu tüm IAsyncEnumerable<Tᵢ> türleri arasında, TT olmadığı ve diğer tüm dynamic türleri için Tᵢ'den IAsyncEnumerable<T>'e örtük bir dönüştürme olduğu benzersiz bir tür IAsyncEnumerable<Tᵢ> varsa, koleksiyon türü arabirimi IAsyncEnumerable<T>, numaralandırıcı türü arabirimi IAsyncEnumerator<T> ve yineleme türü T olur.
    • Aksi takdirde, Tbirden fazla tür varsa bir hata üretilir ve başka bir adım atılmaz.
    • Aksi takdirde bir hata oluşturulur ve başka bir adım atılmaz.

Başarıyla gerçekleştirildiğinde yukarıdaki adımlar, açık bir şekilde Ckoleksiyon türü, E enumerator türü ve Tyineleme türü oluşturur. await foreach Formun deyimi

await foreach (V v in x) «embedded_statement»

daha sonra şu değerle eşdeğerdir:

{
    E e = ((C)(x)).GetAsyncEnumerator();
    try
    {
        while (await e.MoveNextAsync())
        {
            V v = (V)(T)e.Current;
            «embedded_statement»
        }
    }
    finally
    {
        ... // Dispose e
    }
}

Değişken e , ifade x veya ekli deyim ya da programın başka bir kaynak kodu için görünür veya erişilebilir değildir. Değişken v, gömülü deyimde salt okunurdur. (yineleme türü) ile T arasında, V deyimindeki local_variable_type için açık bir dönüştürme (await foreach) yoksa, bir hata üretilir ve başka bir adım atılmaz.

Zaman uyumsuz bir numaralandırıcı, isteğe bağlı olarak bağımsız değişken almadan çağrılabilen ve döndürdüğünde DisposeAsync edilebilen ve await'sinin GetResult() döndürdüğü bir void yöntemini sunabilir.

foreach biçiminde bir ifade

await foreach (T item in enumerable) «embedded_statement»

şu şekilde genişletilir:

var enumerator = enumerable.GetAsyncEnumerator();
try
{
    while (await enumerator.MoveNextAsync())
    {
       T item = enumerator.Current;
       «embedded_statement»
    }
}
finally
{
    await enumerator.DisposeAsync(); // omitted, along with the try/finally,
                            // if the enumerator doesn't expose DisposeAsync
}

13.10 Jump ifadeleri

13.10.1 Genel

Jump deyimleri koşulsuz olarak denetimi aktarır.

jump_statement
    : break_statement
    | continue_statement
    | goto_statement
    | return_statement
    | throw_statement
    ;

Atlama deyiminin denetimi aktardığı konum, atlama deyiminin hedefi olarak adlandırılır.

Bir atlama deyimi bir blok içinde gerçekleştiğinde ve bu atlama deyiminin hedefi bu bloğun dışında olduğunda, atlama deyiminin bloktan çıktığı söylenir. Atlama deyimi kontrolü bir bloğun dışına aktarırken, hiçbir zaman kontrolü bir bloğa aktaramaz.

Atlama ifadelerinin yürütülmesi, araya giren try ifadelerin varlığıyla karmaşıklaşır. Bu tür try deyimlerin olmaması halinde, bir atlama deyimi, denetimi atlama deyiminden hedefine koşulsuz olarak aktarır. Bu tür araya giren try deyimlerin varlığında yürütme daha karmaşıktır. Atlama deyimi, ilişkili try bloklara sahip bir veya daha fazla finally bloktan çıkarsa, denetim başlangıçta finally deyimin en içteki try bloğuna aktarılır. Bir finally bloğunun bitiş noktasına ulaşıldığında ve bu gerçekleştiğinde, kontrol bir sonraki kapsayan finally deyiminin try bloğuna aktarılır. Bu işlem, tüm araya gelen finally ifadelerin try blokları yürütülene kadar yinelenir.

Örnek: Aşağıdaki kodda

class Test
{
    static void Main()
    {
        while (true)
        {
            try
            {
                try
                {
                    Console.WriteLine("Before break");
                    break;
                }
                finally
                {
                    Console.WriteLine("Innermost finally block");
                }
            }
            finally
            {
                Console.WriteLine("Outermost finally block");
            }
        }
        Console.WriteLine("After break");
    }
}

finally iki try deyimle ilişkili bloklar, denetim atlama deyiminin hedefine aktarilmeden önce yürütülür. Üretilen çıkış aşağıdaki gibidir:

Before break
Innermost finally block
Outermost finally block
After break

son örnek

13.10.2 Break ifadesi

En yakın kapsayan break, switch, while, do veya for deyiminden foreach deyimi çıkar.

break_statement
    : 'break' ';'
    ;

Bir break deyiminin hedefi, en yakın kapsayan switch, , whiledo, forveya foreach deyiminin bitiş noktasıdır. Bir break deyimi switch, while, do, for veya foreach deyimiyle kapatılmazsa, derleme hatası oluşur.

Birden çok switch, while, do, , forveya foreach deyimi iç içe geçtiğinde, bir break deyim yalnızca en içteki deyim için geçerlidir. Denetimi birden çok iç içe geçme düzeyinde aktarmak için bir goto deyim (§13.10.4) kullanılmalıdır.

Bir break ifade bir finally bloktan (§13.11) çıkış yapamaz. Bir break deyim bir finally blok içinde gerçekleştiğinde, deyiminin break hedefi aynı finally blok içinde olmalıdır; aksi takdirde bir derleme zamanı hatası oluşur.

Bir break ifadesi aşağıdaki gibi yürütülür:

  • Eğer break deyimi, ilişkili try bloklarla bir veya daha fazla finally bloktan çıkarsa, denetim başlangıçta en içteki finally deyiminin try bloğuna aktarılır. Bir finally bloğunun bitiş noktasına ulaşıldığında ve bu gerçekleştiğinde, kontrol bir sonraki kapsayan finally deyiminin try bloğuna aktarılır. Bu işlem, tüm araya gelen finally ifadelerin try blokları yürütülene kadar yinelenir.
  • Denetim, break deyiminin hedefine aktarılır.

Bir break deyim, denetimi koşulsuz olarak başka bir yere aktardığından, deyiminin break bitiş noktasına hiçbir zaman ulaşılamaz.

13.10.3 Continue deyimi

continue deyimi, en yakın kapsayan while, do, for veya foreach deyiminin yeni bir yinelemesini başlatır.

continue_statement
    : 'continue' ';'
    ;

continue deyiminin hedefi, en yakın kapsayan while, do, for veya foreach deyiminin gömülü deyiminin bitiş noktasıdır. Bir continue deyimi, while, do, for veya foreach deyimiyle kapatılmazsa, derleme zamanı hatası oluşur.

Birden çok while, do, forveya foreach deyimi birbirinin içine yerleştirildiğinde, bir continue deyim yalnızca en içteki deyime uygulanır. Denetimi birden çok iç içe geçme düzeyinde aktarmak için bir goto deyim (§13.10.4) kullanılmalıdır.

Bir continue ifade bir finally bloktan (§13.11) çıkış yapamaz. Bir continue deyim bir finally blok içinde gerçekleştiğinde, deyiminin continue hedefi aynı finally blok içinde olmalıdır; aksi takdirde bir derleme zamanı hatası oluşur.

Bir continue ifadesi aşağıdaki gibi yürütülür:

  • Eğer continue deyimi, ilişkili try bloklarla bir veya daha fazla finally bloktan çıkarsa, denetim başlangıçta en içteki finally deyiminin try bloğuna aktarılır. Bir finally bloğunun bitiş noktasına ulaşıldığında ve bu gerçekleştiğinde, kontrol bir sonraki kapsayan finally deyiminin try bloğuna aktarılır. Bu işlem, tüm araya gelen finally ifadelerin try blokları yürütülene kadar yinelenir.
  • Denetim, continue deyiminin hedefine aktarılır.

Bir continue deyim, denetimi koşulsuz olarak başka bir yere aktardığından, deyiminin continue bitiş noktasına hiçbir zaman ulaşılamaz.

13.10.4 Goto deyimi

goto ifadesi, kontrolü bir etiketle işaretlenmiş olan başka bir deyime aktarır.

goto_statement
    : 'goto' identifier ';'
    | 'goto' 'case' constant_expression ';'
    | 'goto' 'default' ';'
    ;

goto deyiminin hedefi, belirtilen etikete sahip etiketli deyimdir. Verilen ada sahip bir etiket şu anki fonksiyon üyesinde yoksa veya goto ifadesi etiket kapsamında değilse, derleme sırasında bir hata oluşur.

Not: Bu kural, iç içe geçmiş bir goto denetimi aktarmak için bir deyimin kullanılmasına izin verir, ancak iç içe geçmiş bir kapsama aktarılmaz. Örnekte

class Test
{
    static void Main(string[] args)
    {
        string[,] table =
        {
            {"Red", "Blue", "Green"},
            {"Monday", "Wednesday", "Friday"}
        };
        foreach (string str in args)
        {
            int row, colm;
            for (row = 0; row <= 1; ++row)
            {
                for (colm = 0; colm <= 2; ++colm)
                {
                    if (str == table[row,colm])
                    {
                        goto done;
                    }
                }
            }
            Console.WriteLine($"{str} not found");
            continue;
          done:
            Console.WriteLine($"Found {str} at [{row}][{colm}]");
        }
    }
}

bir goto ifadeyi iç içe geçmiş bir kapsamın dışına denetim aktarmak için kullanılır.

dipnot

Deyimin goto case hedefi, verilen sabit değerin sabit desenine ve koruyucu olmayan bir switch etikete sahip bir deyim listesi içeren hemen üstteki deyimidir (case). goto case Deyimi bir switch deyimi içine alınmamışsa, en yakın kapsayan switch deyim böyle bir case içermediyse veya constant_expression örtük olarak en yakın kapsayan deyimin yöneten türüne dönüştürülebilir değilse (switch), bir derleme zamanı hatası oluşur.

goto default ifadesinin hedefi, switch etiketini içeren deyim listesini barındıran en yakın ifadesidir (default). goto default deyimi bir switch deyiminin içine alınmamışsa veya en yakın kapsayan switch deyim bir default etiket içermiyorsa, derleme zamanı hatası oluşur.

Bir goto ifade bir finally bloktan (§13.11) çıkış yapamaz. Bir goto deyim bir finally blok içinde gerçekleştiğinde, deyimin goto hedefi aynı finally blok içinde olacaktır veya başka bir şekilde derleme zamanı hatası oluşur.

Bir goto ifadesi aşağıdaki gibi yürütülür:

  • Eğer goto deyimi, ilişkili try bloklarla bir veya daha fazla finally bloktan çıkarsa, denetim başlangıçta en içteki finally deyiminin try bloğuna aktarılır. Bir finally bloğunun bitiş noktasına ulaşıldığında ve bu gerçekleştiğinde, kontrol bir sonraki kapsayan finally deyiminin try bloğuna aktarılır. Bu işlem, tüm araya gelen finally ifadelerin try blokları yürütülene kadar yinelenir.
  • Denetim, goto deyiminin hedefine aktarılır.

Bir goto deyim, denetimi koşulsuz olarak başka bir yere aktardığından, deyiminin goto bitiş noktasına hiçbir zaman ulaşılamaz.

13.10.5 Return deyimi

Dönüş deyimi, isteğe bağlı olarak bir değer veya return (§9.5) döndürebilir ve dönüş deyiminin geçtiği işlev üyesinin mevcut çağıranına kontrolü geri döndürür.

return_statement
    : 'return' ';'
    | 'return' expression ';'
    | 'return' 'ref' variable_reference ';'
    ;

İfade içermeyen bir return_statementdeğer döndürmeyen olarak adlandırılır; refifade içeren birine referansla dönüş denir; ve sadece ifade içeren birinedeğerle dönüş denir.

Çıktı olarak değer döndürmeyen bir metodu, değere göre veya başvuruya göre dönen (başv) olarak bildirildiği durumlarda kullanmak derleme zamanı hatasıdır (§15.6.1).

Değer döndürmeyen veya değer döndüren olarak bildirilen bir yöntemden referansla dönüş kullanılması derlemede bir hataya yol açar.

Değer döndürmeyen veya referansla dönen olarak tanımlanmış bir yöntemden değer döndürme kullanmak derleme zamanı hatasıdır.

İfade bir variable_reference değilse veya ref-güvenli bağlamı çağıran bağlamla aynı olmayan bir değişkene referanssa (§9.7.2), referansla dönen bir dönüş kullanmak derleme zamanı hatasıdır.

method_modifierasync ile bildirilen bir yöntemden referans döndüren bir dönüş kullanmak derleme zamanı hatasıdır.

İşlev üyesinin, değere göre dönüş yöntemi (§15.6.11), bir özellik veya dizin oluşturucunun değere göre dönüş alma erişimcisi veya kullanıcı tanımlı işleci olan bir yöntemse değeri hesapladığı söylenir. Değer döndürmeyen işlev üyeleri bir değeri hesaplamaz ve etkin dönüş türüne voidsahip yöntemlerdir, özelliklerin ve dizin oluşturucuların erişimcilerini ayarlar, olayların erişimcilerini, örnek oluşturucularını, statik oluşturucuları ve sonlandırıcıları ekleyip kaldırır. Referans olarak dönen işlev üyeleri bir değeri hesaplamaz.

Değere dönüş için, ifade türünden içeren işlev üyesinin etkin dönüş türüne (§15.6.11) örtük dönüştürme (§10.2) bulunacaktır. Başvuru ile dönüş için, ifade türü ile içeren işlev üyesinin etkin dönüş türü arasında bir kimlik dönüştürmesi (§10.2.2) bulunmalıdır.

return deyimleri anonim işlev ifadelerinin gövdesinde de kullanılabilir (§12.19) ve bu işlevler için hangi dönüştürmelerin mevcut olduğunu belirlemeye katılabilir (§10.7.1).

Bir return deyiminin bir finally bloğunda görünmesi bir derleme zamanı hatasıdır (§13.11).

Bir return ifadesi aşağıdaki gibi yürütülür:

  • Bir değere dönüş için ifade değerlendirilir ve değeri örtük bir dönüştürme ile içeren işlevin etkin dönüş türüne dönüştürülür. Dönüştürmenin sonucu, işlev tarafından üretilen sonuç değeri olur. "Referansla dönüş için, ifade değerlendirilir ve sonuç bir değişken olarak sınıflandırılmalıdır." Eğer kapsayan yöntemin başvuru ile dönüşü readonly içeriyorsa, sonuçta elde edilen değişken salt okunurdur.
  • Deyim, bir veya daha fazla return veya try blokla birlikte ilişkili catch blokların içine alınmışsa, denetim başlangıçta en içteki finally deyimin finally bloğuna aktarılır. Bir finally bloğunun bitiş noktasına ulaşıldığında ve bu gerçekleştiğinde, kontrol bir sonraki kapsayan finally deyiminin try bloğuna aktarılır. Bu işlem, tüm kapsayıcı finally deyimlerin try blokları yürütülene kadar yinelenir.
  • İçeren işlev zaman uyumsuz bir işlev değilse, denetim varsa sonuç değeriyle birlikte içeren işlevin çağırıcısına döndürülür.
  • Bu işlevi içeren işlev bir async işlevse, kontrol mevcut çağırıcıya geri döner ve varsa sonuç değeri, (§15.14.3) içinde açıklandığı gibi dönüş görevine yazılır.

Bir return deyim, denetimi koşulsuz olarak başka bir yere aktardığından, deyiminin return bitiş noktasına hiçbir zaman ulaşılamaz.

13.10.6 Throw deyimi

throw ifadesi bir istisna oluşturur.

throw_statement
    : 'throw' expression? ';'
    ;

İfade içeren bir throw deyimi, ifadenin değerlendirilmesiyle üretilen özel bir durum fırlatır. İfade örtük şekilde System.Exception'ye dönüştürülebilir ve ifadenin değerlendirilmesinin sonucu, önce System.Exception'e dönüştürülüp sonra atılır. Dönüştürmenin sonucu null ise, bunun yerine bir System.NullReferenceException atılır.

throw İfade içermeyen bir deyim yalnızca bir catch blokta kullanılabilir, bu durumda bu deyim şu anda bu catch blok tarafından işlenen istisnayı yeniden fırlatır.

Bir throw deyim, denetimi koşulsuz olarak başka bir yere aktardığından, deyiminin throw bitiş noktasına hiçbir zaman ulaşılamaz.

Özel durum fırlatıldığında, denetim özel durumu işleyebilen bir kapsayıcı catch deyimdeki ilk try yan tümcesine aktarılır. Özel durumun oluştuğu noktadan denetimi uygun bir özel durum işleyicisine aktarma noktasına kadar geçen işlem, özel durum yayma olarak bilinir. Bir özel durumun yayılması, özel durumla eşleşen bir catch yan tümce bulunana kadar aşağıdaki adımların tekrar tekrar değerlendirilmesini içerir. Bu açıklamada, fırlatma noktası başlangıçta özel durumun fırlatıldığı konumdur. Bu davranış (§21.4) içinde belirtilir.

  • Geçerli fonksiyon üyesinde, atılan noktayı kapsayan her try deyim incelenir. Her bir ifade S için, en içteki try ifadeden başlayarak en dıştaki try ifadeye kadar, aşağıdaki adımlar değerlendirilir:

    • Eğer try bloğu S, atma noktasını kapatıyorsa ve S bir veya daha fazla catch yan tümcesine sahipse, catch yan tümceler uygun bir işleyiciyi bulmak için görünüm sırasına göre incelenir. Çalışma zamanı türü catch, T'den türetiliyorsa bir eşleşme kabul edilen, bir özel durum türü T (veya çalışma zamanında bir özel durum türünü belirten tür parametresi E) tanımlayan ilk T yan tümce. Yan tümcesi bir özel durum filtresi içeriyorsa, özel durum nesnesi özel durum değişkenine atanır ve özel durum filtresi değerlendirilir. Bir catch yan tümce bir özel durum filtresi içerdiğinde, eğer bu özel durum filtresi catch olarak değerlendirilirse, bu true yan tümce eşleşme olarak kabul edilir. Genel catch (§13.11) yan tümcesi, herhangi bir özel durum türü için eşleşme olarak kabul edilir. Eşleşen catch bir yan tümce bulunursa, denetimi bu catch yan tümcenin bloğuna aktararak özel durum yayma işlemi tamamlanır.
    • Aksi takdirde, try bloğu veya bir catch bloğu S atma noktasını kapatıyorsa ve S'ün bir finally bloğu varsa, denetim finally bloğuna aktarılır. finally Blok başka bir özel durum oluşturursa geçerli özel durumun işlenmesi sonlandırılır. Aksi takdirde, denetim bloğun finally bitiş noktasına ulaştığında geçerli özel durumun işlenmesine devam edilir.
  • Geçerli işlev çağrısında bir özel durum işleyicisi bulunmadıysa, işlev çağrısı sonlandırılır ve aşağıdakilerden biri gerçekleşir:

    • Geçerli işlev zaman uyumsuz değilse, yukarıdaki adımlar, işlev üyesinin çağrıldığı deyime karşılık gelen bir fırlatma noktasıyla işlevi çağıran için yinelenir.

    • Geçerli işlev zaman uyumsuz ve görev döndürense, özel durum , §15.14.3'te açıklandığı gibi hatalı veya iptal edilmiş duruma konulan dönüş görevine kaydedilir.

    • Geçerli işlev senkronize olmayan ve void-dönüşlü ise, geçerli iş parçacığının senkronizasyon bağlamı, §15.14.4'te açıklandığı gibi bildirilir.

  • Özel durum işleme geçerli iş parçacığındaki tüm işlev üyesi çağrılarını sonlandırırsa ve iş parçacığının özel durum için işleyicisi olmadığını gösterirse, iş parçacığının kendisi sonlandırılır. Bu sonlandırmanın etkisi uygulamaya bağlıdır.

13.11 Try deyimi

deyimi, try bir bloğun yürütülmesi sırasında oluşan özel durumları yakalamak için bir mekanizma sağlar. Ayrıca try deyimi, denetim try deyiminden ayrıldığında her zaman yürütülen bir kod bloğunu belirtme olanağı sağlar.

try_statement
    : 'try' block catch_clauses
    | 'try' block catch_clauses? finally_clause
    ;

catch_clauses
    : specific_catch_clause+
    | specific_catch_clause* general_catch_clause
    ;

specific_catch_clause
    : 'catch' exception_specifier exception_filter? block
    | 'catch' exception_filter block
    ;

exception_specifier
    : '(' type identifier? ')'
    ;

exception_filter
    : 'when' '(' boolean_expression ')'
    ;

general_catch_clause
    : 'catch' block
    ;

finally_clause
    : 'finally' block
    ;

try_statement anahtar sözcüğünden try sonra bir blok, ardından sıfır veya daha fazla catch_clauses ve ardından isteğe bağlı bir finally_clause oluşur. En az bir catch_clause veya finally_clause olacaktır.

Bir exception_specifier'da bulunan türü veya type_parameter ise geçerli temel sınıfı, System.Exception veya ondan türeyen bir tür olmalıdır.

Yan catch tümcesi hem class_type hem de tanımlayıcıyı belirttiğinde, verilen ad ve türün bir özel durum değişkeni bildirilir. Özel durum değişkeni , specific_catch_clause bildirim alanına (§7.3) eklenir. exception_filter ve catch bloğun yürütülmesi sırasında, özel durum değişkeni şu anda işlenen özel durumu temsil eder. Kesin atama denetimi amacıyla, özel durum değişkeninin kapsamın tamamında kesinlikle atandığı kabul edilir.

Yan catch tümcesi bir özel durum değişkeni adı içermediği sürece, filtre ve catch bloktaki özel durum nesnesine erişmek mümkün değildir.

Ne catch bir özel durum türü ne de özel durum değişkeni adı belirten bir yan tümce genel catch yan tümcesi olarak adlandırılır. Bir try ifadenin yalnızca bir genel catch şartı olabilir ve varsa, son catch madde olacaktır.

Not: Bazı programlama dilleri, öğesinden System.Exceptiontüretilen bir nesne olarak temsil edilemeyen özel durumları desteklese de, bu tür özel durumlar hiçbir zaman C# kodu tarafından oluşturulamaz. Bu tür özel durumları yakalamak için genel catch bir ifade kullanılabilir. Bu nedenle, genel bir catch yan tümce, türünü System.Exception belirten bir yan tümceden anlamsal olarak farklıdır; çünkü ilki, diğer dillerden gelen istisnaları da yakalayabilir. dipnot

Bir özel durumun işleyicisini bulmak için catch koşulları dizgisel sırayla incelenir. Aynı catch deyiminin önceki catch bloğu bir tür belirtiyor ancak özel durum filtresi içermiyorsa, sonraki try bloğunun bu türle aynı olan veya türetilmiş bir türü belirtmesi bir derleme zamanı hatasına neden olur.

Not Bu kısıtlama olmadan ulaşılamayan catch koşullar yazılabilir. dipnot

Bir catch blok içinde, throw bloğu tarafından yakalanmış olan istisnayı yeniden fırlatmak için ifade içermeyen bir deyimi (catch) kullanılabilir. Bir özel durum değişkenine yapılan atamalar, yeniden oluşan özel durumu değiştirmez.

Örnek: Aşağıdaki kodda

class Test
{
    static void F()
    {
        try
        {
            G();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception in F: " + e.Message);
            e = new Exception("F");
            throw; // re-throw
        }
    }

    static void G() => throw new Exception("G");

    static void Main()
    {
        try
        {
            F();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception in Main: " + e.Message);
        }
    }
}

yöntemi F bir özel durum yakalar, konsola bazı tanılama bilgileri yazar, özel durum değişkenini değiştirir ve özel durumu yeniden oluşturur. Yeniden oluşturulan özel durum özgün özel durumdur, bu nedenle üretilen çıkış şöyledir:

Exception in F: G
Exception in Main: G

Eğer ilk catch blok, geçerli özel durumu yeniden fırlatmak yerine e fırlatsaydı, üretilen çıkış şöyle olurdu:

Exception in F: G
Exception in Main: F

son örnek

break, continue veya goto deyiminin, bir finally bloğunun dışına denetimi aktarması derleme zamanı hatasıdır. Bir break, continueveya goto deyimi bir finally blokta oluştuğunda, deyimin hedefi aynı finally blok içinde olacaktır veya başka bir şekilde derleme zamanı hatası oluşur.

Bir return deyiminin bir finally blok içinde yer alması derleme zamanı hatasıdır.

Yürütme bir try deyime ulaştığında, denetim bloğuna try aktarılır. Denetim, bir hata yayılmadan try bloğunun bitiş noktasına ulaşırsa, varsa kontrol finally bloğuna aktarılır. Blok finally yoksa, kontrol try deyiminin bitiş noktasına devredilir.

Bir istisna iletildiyse, catch belirtilmişse yan tümceler, istisna için ilk eşleşmeyi arayarak sözdizimsel sırayla incelenir. Eşleşen catch yan tümcenin aranması, §13.10.6'da açıklandığı gibi, tüm kapsayan bloklarla sürdürülür. Bir catch yan tümce, özel durum türü herhangi bir exception_specifier ile eşleştiğinde ve herhangi bir exception_filter doğru olduğunda eşleşir. catch kabul yan tümcesi exception_specifier olmadan herhangi bir özel durum türüyle eşleşir. Özel durum türü, özel_durum_belirleyicisi özel durum türünü veya özel durum türünün temel türünü belirttiğinde özel_durum_belirleyicisi ile eşleşir. Yan tümcesi bir özel durum filtresi içeriyorsa, özel durum nesnesi özel durum değişkenine atanır ve özel durum filtresi değerlendirilir.

Bir özel durum yayılırsa ve eşleşen bir catch yan tümce bulunursa, denetim ilk eşleşen catch bloğa aktarılır. Denetim, bir hata yayılmadan catch bloğunun bitiş noktasına ulaşırsa, varsa kontrol finally bloğuna aktarılır. Blok finally yoksa, kontrol try deyiminin bitiş noktasına devredilir. Eğer bir istisna catch bloğundan yayılmışsa, bir finally bloğu mevcutsa, kontrol finally bloğuna aktarılır. Özel durum, sonraki kapsayan try deyime yayılır.

Bir özel durum yayılırsa ve eşleşen catch yan tümcesi bulunmazsa, finally bloğu varsa kontrol aktarılır. Özel durum, sonraki kapsayan try deyime yayılır.

finally bloğunun deyimleri, kontrol try deyiminden çıktığında her zaman yürütülür. Denetim aktarımının normal yürütmenin bir sonucu olarak, bir , break, continueveya deyiminin yürütülmesinin gotosonucu olarak veya return deyimin try dışına bir özel durum yayma sonucu olup olmadığı doğrudur. Denetim, bir özel durum yayılmadan bloğun finally bitiş noktasına ulaşırsa, denetim deyiminin try bitiş noktasına aktarılır.

Bir finally bloğunun yürütülmesi sırasında bir özel durum ortaya çıkarsa ve aynı finally blok içinde yakalanmazsa, bu özel durum bir sonraki kapsayıcı try deyime iletilir. Başka bir özel durum yayılma sürecindeyse, bu özel durum kaybolur. Özel durum yayma işlemi, deyiminin throw açıklamasında daha ayrıntılı olarak ele alınıyor (§13.10.6).

Örnek: Aşağıdaki kodda

public class Test
{
    static void Main()
    {
        try
        {
            Method();
        }
        catch (Exception ex) when (ExceptionFilter(ex))
        {
            Console.WriteLine("Catch");
        }

        bool ExceptionFilter(Exception ex)
        {
            Console.WriteLine("Filter");
            return true;
        }
    }

    static void Method()
    {
        try
        {
            throw new ArgumentException();
        }
        finally
        {
            Console.WriteLine("Finally");
        }
    }
}

yöntemi Method bir özel durum oluşturur. İlk eylem, kapsayıcı catch yan tümceleri inceleyerek ve herhangi bir özel durum filtresi yürütmektir. Ardından, finally içindeki Method yan tümcesi, kontrol kapsayan eşleşen catch yan tümceye aktarılmadan önce yürütülür. Sonuçta elde edilen çıktı:

Filter
Finally
Catch

son örnek

try bloğu, try deyimine ulaşılabiliyorsa, bir try deyimine ulaşılabilir.

Deyimine catch ulaşılabilirse, try deyiminin bloğuna try ulaşılabilir.

finally bloğu, try deyimine ulaşılabiliyorsa, bir try deyimine ulaşılabilir.

Aşağıdakilerin her ikisi de doğruysa deyiminin try bitiş noktasına ulaşılabilir:

  • Bloğun try bitiş noktasına ulaşılabilir veya en az bir catch bloğun bitiş noktasına ulaşılabilir.
  • Bir finally blok varsa bloğun finally bitiş noktasına ulaşılabilir.

13.12 İşaretli ve işaretlenmemiş deyimler

checked ve unchecked ifadeleri, tamsayı türü aritmetik işlemler ve dönüştürmeler için taşma denetleme bağlamını kontrol etmek için kullanılır.

checked_statement
    : 'checked' block
    ;

unchecked_statement
    : 'unchecked' block
    ;

checked deyimi, bloktaki tüm ifadelerin denetlenen bir bağlamda değerlendirilmesine neden olur ve unchecked deyimi, bloktaki tüm ifadelerin kontrolsüz bir bağlamda değerlendirilmesine neden olur.

checked ve unchecked ifadeleri, ifadeler yerine bloklar üzerinde çalışması dışında checked ve unchecked işleçlerine (§12.8.20) tam olarak eşdeğerdir.

13.13 Kilit deyimi

lock ifadesi belirli bir nesne için karşılıklı dışlama kilidini elde eder, ifadeyi yürütür ve sonra kilidi serbest bırakır.

lock_statement
    : 'lock' '(' expression ')' embedded_statement
    ;

Bir deyiminin lock, başvuru olarak bilinen türde bir değeri belirtir. deyiminin ifadesi için hiçbir örtük kutulama dönüşümü (lock) gerçekleştirilmez, bu nedenle ifadenin bir value_type değeri belirtmesi derleme zamanı hatasıdır.

lock biçiminde bir ifade

lock (x)...

burada x bir reference_type ifadesidir, tam olarak şunun eşdeğeridir:

bool __lockWasTaken = false;
try
{
    System.Threading.Monitor.Enter(x, ref __lockWasTaken);
    ...
}
finally
{
    if (__lockWasTaken)
    {
        System.Threading.Monitor.Exit(x);
    }
}

ancak x yalnızca bir kez değerlendirilir.

Karşılıklı dışlama kilidi tutuluyorken, aynı yürütme iş parçacığında çalışan kod da kilidi alabilir ve serbest bırakabilir. Ancak, diğer iş parçacıklarında yürütülen kodun kilit serbest bırakılana kadar kilidi alması engellenir.

13.14 using deyimi

using deyimi, bir veya daha fazla kaynağı alır, bir deyimi yürütür ve ardından kaynakları atar.

using_statement
    : 'using' '(' resource_acquisition ')' embedded_statement
    ;

resource_acquisition
    : local_variable_declaration
    | expression
    ;

A kaynak, zaman uyumsuz akışlar için System.IDisposable ve diğer durumlar için IAsyncDisposable arabirimini uygulayan ve zaman uyumsuz akışlar için Dispose ve diğer durumlar için DisposeAsync adında tek bir parametresiz yöntemi içeren bir sınıf veya yapıdır. Kaynak kullanan kod, kaynağın artık gerekli olmadığını belirtmek için çağrısı Dispose yapabilir.

resource_acquisition biçimi local_variable_declaration ise local_variable_declaration türü ya dynamic ya da System.IDisposable'e örtük olarak dönüştürülebilen bir tür olmalıdır (IAsyncDisposable zaman uyumsuz akışlar için). resource_acquisition biçimi ifade ise, bu ifade örtük olarak System.IDisposable olarak dönüştürülebilir olmalıdır (IAsyncDisposable zaman uyumsuz akışlar için).

Bir resource_acquisition'da tanımlanan yerel değişkenler salt okunur olup başlatıcı bir değer içermelidir. Katıştırılmış deyim bu yerel değişkenleri değiştirmeyi denerse (atama veya ++ ve -- işleçleri aracılığıyla), bunların adresini alırsa veya bunları başvuru veya çıkış parametresi olarak geçirirse derleme zamanı hatası oluşur.

Bir using deyim üç bölüme çevrilir: alım, kullanım ve elden çıkarma. Kaynağın kullanımı, bir try yan tümce içeren finally deyimi içine örtük olarak alınır. Bu finally madde kaynağın atılmasını sağlar. Eğer bir null kaynak alınırsa, Dispose çağrısı yapılmaz (DisposeAsync zaman uyumsuz akışlar için) ve özel durum atılmaz. Kaynak türü dynamic ise, dönüştürmenin kullanım ve elden çıkarma işleminden önce başarılı olduğundan emin olmak için edinim sırasında (IDisposable zaman uyumsuz akışlar için) şeklinde örtük dinamik dönüşüm (IAsyncDisposable) yoluyla dinamik olarak dönüştürülür.

using biçiminde bir ifade

using (ResourceType resource = «expression» ) «statement»

üç olası genişletmeden birine karşılık gelir. Null değer atanamayan bir değer türü veya değer türü kısıtlamasına (ResourceType) sahip bir tür parametresi olduğunda, genişletme anlamsal olarak eşdeğerdir.

{
    ResourceType resource = «expression»;
    try
    {
        «statement»;
    }
    finally
    {
        ((IDisposable)resource).Dispose();
    }
}

resource'nın System.IDisposable'e dökümünün boxing'e neden olmaması gerekir.

Aksi takdirde, ResourceTypedynamic olduğunda, genişleme

{
    ResourceType resource = «expression»;
    IDisposable d = resource;
    try
    {
        «statement»;
    }
    finally
    {
        if (d != null)
        {
            d.Dispose();
        }
    }
}

Aksi takdirde, genişleme şöyledir:

{
    ResourceType resource = «expression»;
    try
    {
        «statement»;
    }
    finally
    {
        IDisposable d = (IDisposable)resource;
        if (d != null)
        {
            d.Dispose();
        }
    }
}

Herhangi bir genişletmede, katıştırılmış deyimdeki resource değişkeni salt okunurdur ve d değişkenine erişilemez ve bu deyimde görünmez.

Bir uygulamanın, davranış yukarıdaki genişletmeyle tutarlı olduğu sürece performans nedenleriyle belirli bir using_statement farklı bir şekilde uygulamasına izin verilir.

using yapısında bir ifade:

using («expression») «statement»

aynı üç olası genişletmeye sahiptir. Bu durumda, ResourceType derleme zamanı türü, eğer varsa, ile örtük olarak belirlenir. Aksi takdirde, arabirimin kendisi IDisposable (IAsyncDisposable asenkron akışlar için) ResourceType olarak kullanılır. resource değişkenine erişilemez ve ekli deyimde görünmez.

resource_acquisition bir local_variable_declaration biçimini aldığında, belirli bir türde birden çok kaynak elde etmek mümkündür. using biçiminde bir ifade

using (ResourceType r1 = e1, r2 = e2, ..., rN = eN) «statement»

tam anlamıyla iç içe geçmiş using ifade dizisine eşdeğerdir:

using (ResourceType r1 = e1)
using (ResourceType r2 = e2)
...
using (ResourceType rN = eN)
«statement»

Örnek: Aşağıdaki örnek log.txt adlı bir dosya oluşturur ve dosyaya iki satır metin yazar. Örnek daha sonra okumak için aynı dosyayı açar ve içerdiği metin satırlarını konsola kopyalar.

class Test
{
    static void Main()
    {
        using (TextWriter w = File.CreateText("log.txt"))
        {
            w.WriteLine("This is line one");
            w.WriteLine("This is line two");
        }
        using (TextReader r = File.OpenText("log.txt"))
        {
            string s;
            while ((s = r.ReadLine()) != null)
            {
                Console.WriteLine(s);
            }
        }
    }
}

TextWriter ve TextReader sınıfları IDisposable arayüzünü uyguladığı için, örnek, temel alınan dosyanın yazma veya okuma operasyonlarının ardından düzgün bir şekilde kapatılmasını sağlamak için using ifadelerini kullanabilir.

son örnek

13.15 Ödeme tablosu

deyimi yield , bir yineleyicinin numaralandırıcı nesnesine (§15.15.5) veya numaralandırılabilir nesneye (§15.15.6) değer vermek veya yinelemenin sonuna işaret etmek için bir yineleyici bloğunda (§13.3) kullanılır.

yield_statement
    : 'yield' 'return' expression ';'
    | 'yield' 'break' ';'
    ;

yield bağlamsal bir anahtar sözcüktür (§6.4.4) ve yalnızca bir return veya break anahtar sözcüğün hemen öncesinde kullanıldığında özel bir anlamı vardır.

Aşağıda açıklandığı gibi bir yield deyimin nerede görünebileceğine ilişkin çeşitli kısıtlamalar vardır.

  • Bir yield deyiminin (her iki biçimde de) bir method_body, operator_body veya accessor_body dışında görünmesi derleme zamanında hata oluşur.
  • Bir yield deyiminin (her iki biçimde de) anonim bir işlev içinde görünmesi, derleme zamanında bir hatadır.
  • Bir yield deyiminin (her iki biçimde de) finally kuralında görünmesi try derleme zamanı hatasıdır.
  • yield return deyiminin, herhangi bir try içeren bir deyimi içinde herhangi bir yerde görünmesi derleme zamanı hatasıdır.

Örnek: Aşağıdaki örnekte deyimlerin yield bazı geçerli ve geçersiz kullanımları gösterilmektedir.

delegate IEnumerable<int> D();

IEnumerator<int> GetEnumerator()
{
    try
    {
        yield return 1; // Ok
        yield break;    // Ok
    }
    finally
    {
        yield return 2; // Error, yield in finally
        yield break;    // Error, yield in finally
    }
    try
    {
        yield return 3; // Error, yield return in try/catch
        yield break;    // Ok
    }
    catch
    {
        yield return 4; // Error, yield return in try/catch
        yield break;    // Ok
    }
    D d = delegate
    {
        yield return 5; // Error, yield in an anonymous function
    };
}

int MyMethod()
{
    yield return 1;     // Error, wrong return type for an iterator block
}

son örnek

Deyimdeki ifadenin türünden yineleyicinin verim türüne (§15.15.4) örtük dönüştürme (§10.2) bulunacaktır.yield return

Bir yield return ifadesi aşağıdaki gibi yürütülür:

  • deyiminde verilen ifade değerlendirilir, örtük olarak verim türüne dönüştürülür ve numaralandırıcı nesnesinin özelliğine Current atanır.
  • Yineleyici bloğunun yürütülmesi askıya alınır. yield return deyimi bir veya daha fazla try blok içindeyse, ilişkili finally bloklar şu anda yürütülmedi.
  • MoveNext Numaralandırıcı nesnesinin yöntemi, numaralandırıcı nesnesinin sonraki öğeye başarıyla ilerlediğini belirterek çağırana geri dönertrue.

Numaralandırıcı nesnesinin MoveNext yöntemine yapılan sonraki çağrı, yineleyici bloğunun yürütülmesini en son askıya alındığı yerden sürdürür.

Bir yield break ifadesi aşağıdaki gibi yürütülür:

  • Eğer yield break deyimi, ilişkili try bloklara sahip bir veya daha fazla finally blok tarafından içine alındıysa, kontrol başlangıçta en içteki finally deyimin try bloğuna aktarılır. Bir finally bloğunun bitiş noktasına ulaşıldığında ve bu gerçekleştiğinde, kontrol bir sonraki kapsayan finally deyiminin try bloğuna aktarılır. Bu işlem, tüm kapsayıcı finally deyimlerin try blokları yürütülene kadar yinelenir.
  • Yineleyici bloğunun denetimi, çağırana geri döndürülür. Bu, numaralandırıcı nesnesinin MoveNext yöntemi veya Dispose yöntemidir.

Bir yield break deyim, denetimi koşulsuz olarak başka bir yere aktardığından, deyiminin yield break bitiş noktasına hiçbir zaman ulaşılamaz.