Aracılığıyla paylaş


11 Desen ve desen eşleştirme

11.1 Genel

Desen, işleç (is§12.14.12), bir switch_statement (§13.8.3) ve switch_expression (§12.11) ile gelen verilerin karşılaştırılacağı veri şeklini ifade etmek için kullanılabilen söz dizimsel bir formdur. Desenler özyinelemeli olabilir, böylece verilerin bölümleri alt desenlerle eşleştirilebilir.

Desen, çeşitli bağlamlardaki bir değere göre test edilir:

  • Switch deyiminde, bir servis talebi etiketinin deseni switch deyiminin ifadesinde test edilir.
  • bir is-pattern işlecinde, sağ taraftaki desen soldaki ifadeye göre test edilir.
  • Switch ifadesinde, switch_expression_armdeseni switch-expression'ın sol tarafındaki ifadeye göre test edilir.
  • İç içe bağlamlarda alt desen, desen formuna bağlı olarak özelliklerden, alanlardan alınan veya diğer giriş değerlerinden dizine alınan değerlerle test edilir.

Bir desenin sınandığı değer, desen giriş değeri olarak adlandırılır.

11.2 Desen formları

11.2.1 Genel

Bir desen aşağıdaki formlardan birine sahip olabilir:

pattern
    : declaration_pattern
    | constant_pattern
    | var_pattern
    | positional_pattern
    | property_pattern
    | discard_pattern
    ;

Bazı desenleryerel bir değişkenin bildirimiyle sonuçlanabilir.

Her desen formu, desenin uygulanabileceği giriş değerleri için tür kümesini tanımlar. Desen, değerleri P eşleşebilecek türler arasındaysa, T bir tür için geçerlidirT Için geçerli değilse P , bir programda desen giriş değeriyle (§11.1) T eşleşecek şekilde görüntüleniyorsa P derleme zamanı hatasıdır T.

Örnek: Aşağıdaki örnek, derleme zamanı türü v olduğundan TextReaderderleme zamanı hatası oluşturur. Türündeki TextReader bir değişkenin hiçbir zaman ile stringbaşvuru uyumlu bir değeri olamaz:

TextReader v = Console.In; // compile-time type of 'v' is 'TextReader'
if (v is string) // compile-time error
{
    // code assuming v is a string
}

Ancak, derleme zamanı türü v olduğundan objectaşağıdakiler derleme zamanı hatası oluşturmaz. Türünde object bir değişken, ile stringbaşvuru uyumlu bir değere sahip olabilir:

object v = Console.In;
if (v is string s)
{
    // code assuming v is a string
}

son örnek

Her desen formu, desenin çalışma zamanındaki değerle eşleşdiği değer kümesini tanımlar.

Desen eşleştirme sırasında işlemlerin ve yan etkilerin değerlendirilmesi sırası ( Deconstructiçindeki yöntemlerin System.ITupleçağrıları, özellik erişimleri ve çağrıları) belirtilmez.

11.2.2 Bildirim düzeni

declaration_pattern, bir değerin belirli bir türe sahip olup olmadığını test etmek ve test başarılı olursa isteğe bağlı olarak bu türdeki bir değişkende değer sağlamak için kullanılır.

declaration_pattern
    : type simple_designation
    ;
simple_designation
    : discard_designation
    | single_variable_designation
    ;
discard_designation
    : '_'
    ;
single_variable_designation
    : identifier
    ;

Belirteci _ olan bir simple_designation, single_variable_designation yerine discard_designation olarak kabul edilir.

Değerin çalışma zamanı türü, is-type işlecinde (§12.14.12.1) belirtilen kurallar kullanılarak desendeki türe göre test edilir. Test başarılı olursa, desen bu değerle eşleşir . Tür null atanabilir bir değer türü (§8.3.12) veya null atanabilir başvuru türü (§8.9.3) ise derleme zamanı hatasıdır. Bu desen formu hiçbir zaman bir değerle null eşleşmez.

Not: is-type ifadesi e is T ve bildirim deseni e is T _ null atanabilir bir tür olmadığında eşdeğerdir T . son not

Bir desen giriş değeri (§11.1) e verildiğinde, simple_designationdiscard_designation ise atma (§9.2.9.2) değerini belirtir ve e değeri hiçbir şeye bağlı değildir. (Bu noktada adıyla _ bildirilen bir değişken kapsam içinde olsa da, bu adlandırılmış değişken bu bağlamda görülmez.) Aksi takdirde , simple_designationsingle_variable_designation, verilen tanımlayıcı tarafından adlandırılan belirtilen türde bir yerel değişken (§9.2.9) kullanıma sunulur. Bu yerel değişkene, desen değerle eşleştiğinde desen giriş değerinin değeri atanır.

Desen giriş değerinin statik türünün ve verilen türün belirli birleşimleri uyumsuz olarak kabul edilir ve derleme zamanı hatasına neden olur. Statik türdeki E bir değerin, bir kimlik dönüştürmesi, örtük veya açık başvuru dönüştürmesi, bir kutulama dönüştürmesi veya 'den gelen kutulama açma dönüştürmesi varsa ya da açık bir türse TE (T) türüyle E uyumlu desenle uyumluT Bir türü T adlandıran bildirim deseni, geçerlidir.

Not: Açık türler için destek en çok yapı veya sınıf türleri olabilecek türleri denetlerken yararlı olabilir ve kutulamadan kaçınılmalıdır. son not

Örnek: Bildirim deseni, başvuru türlerinin çalışma zamanı türü testlerini gerçekleştirmek için kullanışlıdır ve deyiminin yerini alır

var v = expr as Type;
if (v != null) { /* code using v */ }

biraz daha kısa

if (expr is Type v) { /* code using v */ }

son örnek

Örnek: Bildirim deseni, null atanabilir türlerin değerlerini test etmek için kullanılabilir: değer null olmayan ve Nullable<T>Tise tür deseni T2 id (veya kutuluT2) bir tür deseni T ile eşleşir ya da bazı temel türü veya arabirimi.T Örneğin, kod parçasında

int? x = 3;
if (x is int v) { /* code using v */ }

deyiminin if koşulu çalışma zamanındadır true ve değişkenv, bloğun içindeki türün 3 değerini int tutar. Blok sonrasında değişken v kapsam içindedir, ancak kesinlikle atanmamış olur. son örnek

11.2.3 Sabit deseni

Bir desen giriş değerinin (§11.1) değerini verilen sabit değerle test etmek için bir constant_pattern kullanılır.

constant_pattern
    : constant_expression
    ;

sabit ifadesinden türüne PT geçerlidir.P

Sabit bir desen içinP, dönüştürülen değeri

  • Desen giriş değerinin türü bir tamsayı türü veya bir numaralandırma türüyse, desenin sabit değeri bu türe dönüştürülür; yoksa
  • Desen giriş değerinin türü bir tamsayı türünün veya bir sabit sabit türünün null atanabilir sürümüyse, desenin sabit değeri temel alınan türüne dönüştürülür; yoksa
  • desenin sabit değerinin değeri.

Esahip sabit bir desen P verildiğinde,

  • e tamsayı türüne veya sabit listesi türüne veya bunlardan birinin null atanabilir bir biçimine ve v tamsayı türüne sahipse, ifadenin P sonucu ise desen ; aksi takdirde
  • deseni P.

Örnek: switch Aşağıdaki yöntemdeki deyimi, büyük/küçük harf etiketlerinde beş sabit desen kullanır.

static decimal GetGroupTicketPrice(int visitorCount)
{
    switch (visitorCount) 
    {
        case 1: return 12.0m;
        case 2: return 20.0m;
        case 3: return 27.0m;
        case 4: return 32.0m;
        case 0: return 0.0m;
        default: throw new ArgumentException(...);
    }
}

son örnek

11.2.4 Var deseni

var_pattern her değerle eşleşir. Başka bir ifadeyle, var_pattern ile desen eşleştirme işlemi her zaman başarılı olur.

var_pattern her tür için geçerlidir.

var_pattern
    : 'var' designation
    ;
designation
    : simple_designation
    | tuple_designation
    ;
tuple_designation
    : '(' designations? ')'
    ;
designations
    : designation (',' designation)*
    ;

Bir desen giriş değeri (§11.1) e verildiğinde, atamadiscard_designation ise atılan değeri (§9.2.9.2) belirtir ve e değeri hiçbir şeye bağlı değildir. (Bu ada sahip bildirilen bir değişken bu noktada kapsam içinde olsa da, bu adlandırılmış değişken bu bağlamda görülmez.) Aksi takdirde, atamasingle_variable_designation ise çalışma zamanında e değeri, türü statik e türü olan ve desen giriş değeri bu yerel değişkene atanmış olan bu adın yeni tanıtılan yerel değişkenine (§9.2.9) bağlıdır.

Advar, bir var_pattern kullanıldığı bir türe bağlanacaksa bu bir hatadır.

Atama bir tuple_designation ise, desen form (vargösterimininpositional_pattern (§11.2.5) eşdeğerdir, ... )burada, tuple_designation içinde bulunanlar olarak ifadeedilir. Örneğin, desen var (x, (y, z)) ile (var x, (var y, var z))eşdeğerdir.

11.2.5 Konumsal desen

positional_pattern giriş değerinin olmadığını nulldenetler, uygun Deconstruct bir yöntem (§12.7) çağırır ve sonuçta elde edilen değerlerde daha fazla desen eşleştirmesi gerçekleştirir. Ayrıca, giriş değerinin türü öğesini içeren Deconstructtürle aynı olduğunda veya giriş değerinin türü bir tanımlama grubu türündeyse veya giriş object değerinin türü veya System.ITuple ise ve ifadenin çalışma zamanı türü uygulandığında System.ITupletanımlama grubu benzeri bir desen söz dizimini (sağlanan tür olmadan) destekler.

positional_pattern
    : type? '(' subpatterns? ')' property_subpattern? simple_designation?
    ;
subpatterns
    : subpattern (',' subpattern)*
    ;
subpattern
    : pattern
    | identifier ':' pattern
    ;

Bir giriş değerinin desen türü(alt desenleriyle) eşleşmesi göz önüne alındığında, türü içinde erişilebilir bildirimleri Deconstructaranarak ve bunlar arasında, yapısızlaştırma bildirimiyle aynı kurallar kullanılarak bir yöntem seçilir. Bir positional_pattern türü atlarsa, tanımlayıcısı olmayan tek bir alt sayfaya sahipse, property_subpattern yoksa ve simple_designation yoksa hatadır. Bu, parantez içindeki bir constant_pattern ile positional_pattern arasında ayrımlar. Listedeki desenlerle eşleşecek değerleri ayıklamak için,

  • Tür atlanırsa ve giriş ifadesinin türü bir tanımlama grubu türüyse, alt ekran sayısı tanımlama grubunun kardinalitesi ile aynı olmalıdır. Her tanımlama grubu öğesi karşılık gelen alt çizgiyle eşleştirilir ve bunların tümü başarılı olursa eşleşme başarılı olur. Herhangi bir alt çizginintanımlayıcısı varsa, bu, tanımlama grubu türündeki karşılık gelen konumda bir tanımlama grubu öğesini adlandıracaktır.
  • Aksi takdirde, uygun Deconstruct bir türün üyesi olarak varsa, giriş değerinin türü türle desen uyumlu değilse derleme zamanı hatasıdır. Çalışma zamanında giriş değeri türe göre test edilir. Bu başarısız olursa, konumsal desen eşleşmesi başarısız olur. Başarılı olursa, giriş değeri bu türe dönüştürülür ve Deconstruct çıkış parametrelerini almak için derleyici tarafından oluşturulan yeni değişkenlerle çağrılır. Alınan her değer ilgili alt çizgiyle eşleştirilir ve bunların tümü başarılı olursa eşleşme başarılı olur. Herhangi bir alt belgenintanımlayıcısı varsa, bu, ilgili konumundaki bir parametreyi Deconstructadlandıracaktır.
  • Aksi takdirde, tür atlanırsa ve giriş değeri object türü veya örtük başvuru dönüştürmesi tarafından dönüştürülebilecek System.ITuple bir tür ise ve alt grafikler arasında hiçbir tanımlayıcı görünmezse, eşleşme kullanır System.ITuple.
  • Aksi takdirde, desen bir derleme zamanı hatasıdır.

Çalışma zamanında alt grafiklerin eşleşme sırası belirtilmemiştir ve başarısız bir eşleşme tüm alt grafiklerle eşleşmeye çalışmayabilir.

Örnek: Burada, bir ifade sonucunun yapısını kaldıracak ve sonuçta elde edilen değerleri ilgili iç içe yerleştirilmiş desenlerle eşleştireceğiz:

static string Classify(Point point) => point switch
{
    (0, 0) => "Origin",
    (1, 0) => "positive X basis end",
    (0, 1) => "positive Y basis end",
    _ => "Just a point",
};

public readonly struct Point
{
    public int X { get; }
    public int Y { get; }
    public Point(int x, int y) => (X, Y) = (x, y);
    public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}

son örnek

Örnek: Tanımlama grubu öğelerinin ve Deconstruct parametrelerinin adları aşağıdaki gibi konumsal bir düzende kullanılabilir:

var numbers = new List<int> { 10, 20, 30 };
if (SumAndCount(numbers) is (Sum: var sum, Count: var count))
{
    Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}");
}

static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers)
{
    int sum = 0;
    int count = 0;
    foreach (int number in numbers)
    {
        sum += number;
        count++;
    }
    return (sum, count);
}

Üretilen çıkış şu şekildedir:

Sum of [10 20 30] is 60

son örnek

11.2.6 Özellik düzeni

property_pattern, giriş değerinin olup olmadığını nulldenetler ve erişilebilir özelliklerin veya alanların kullanımıyla ayıklanan değerlerle özyinelemeli olarak eşleşir.

property_pattern
    : type? property_subpattern simple_designation?
    ;
property_subpattern
    : '{' '}'
    | '{' subpatterns ','? '}'
    ;

bir property_patternalt boyasıtanımlayıcı içermiyorsa bu bir hatadır.

Tür null atanabilir bir değer türü (§8.3.12) veya null atanabilir başvuru türü (§8.9.3) ise derleme zamanı hatasıdır.

Not: Null denetim deseni önemsiz bir özellik deseninin dışında kalır. Dizenin s null olmadığını denetlemek için aşağıdaki formlardan herhangi birini yazabilirsiniz:

#nullable enable
string s = "abc";
if (s is object o) ...  // o is of type object
if (s is string x1) ... // x1 is of type string
if (s is {} x2) ...     // x2 is of type string
if (s is {}) ...

son note ifadesininproperty_pattern_list} desen türüyle{ eşleşmesi göz önüne alındığında, e ifadesi türe göre belirlenen T türüyle desen uyumlu değilse derleme zamanı hatasıdır. Tür yoksa, türün statik e türü olduğu varsayılır. property_pattern_list sol tarafında görünen tanımlayıcıların her biri erişilebilir bir okunabilir özellik veya T alanı belirlemeli. property_pattern simple_designation varsa, T türünde bir desen değişkeni bildirir.

Çalışma zamanında ifade T'ye karşı test edilir. Bu başarısız olursa özellik deseni eşleşmesi başarısız olur ve sonuç olur false. Başarılı olursa, her property_subpattern alanı veya özelliği okunur ve değeri ilgili desenle eşleştirilir. Tüm eşleşmenin false sonucu yalnızca bunlardan herhangi birinin sonucu ise olur false. Alt yordamların eşleştirilme sırası belirtilmez ve başarısız bir eşleşme çalışma zamanında tüm alt yordamları test etmeyebilir. Eşleşme başarılı olursa ve property_pattern simple_designation bir single_variable_designation ise, bildirilen değişkene eşleşen değer atanır.

property_pattern, anonim türlerle desen eşleştirmek için kullanılabilir.

Örnek:

var o = ...;
if (o is string { Length: 5 } s) ...

son örnek

Örnek: Aşağıdaki gibi, bir çalışma zamanı türü denetimi ve bir değişken bildirimi bir özellik desenine eklenebilir:

Console.WriteLine(TakeFive("Hello, world!"));  // output: Hello
Console.WriteLine(TakeFive("Hi!"));            // output: Hi!
Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' }));  // output: 12345
Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' }));  // output: abc

static string TakeFive(object input) => input switch
{
    string { Length: >= 5 } s => s.Substring(0, 5),
    string s => s,
    ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
    ICollection<char> symbols => new string(symbols.ToArray()),
    null => throw new ArgumentNullException(nameof(input)),
    _ => throw new ArgumentException("Not supported input type."),
};

Üretilen çıkış şu şekildedir:

Hello
Hi!
12345
abc

son örnek

11.2.7 Atma düzeni

Her ifade atma deseni ile eşleşir ve bu da ifadenin değerinin atılmasıyla sonuçlanır.

discard_pattern
    : '_'
    ;

Form relational_expression deseninin relational_expression atma deseninin kullanılması veya switch_labelisdeseni olarak kullanılması derleme zamanı hatasıdır.

Not: Bu gibi durumlarda, herhangi bir ifadeyi eşleştirmek için at var _ile bir var_pattern kullanın. son not

Örnek:

Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));
Console.WriteLine(GetDiscountInPercent(null));
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));

static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch
{
    DayOfWeek.Monday => 0.5m,
    DayOfWeek.Tuesday => 12.5m,
    DayOfWeek.Wednesday => 7.5m,
    DayOfWeek.Thursday => 12.5m,
    DayOfWeek.Friday => 5.0m,
    DayOfWeek.Saturday => 2.5m,
    DayOfWeek.Sunday => 2.0m,
    _ => 0.0m,
};

Üretilen çıkış şu şekildedir:

5.0
0.0
0.0

Burada, numaralandırmanın karşılık gelen üyesi olmayan tüm tamsayı değerlerini işlemek null için atma deseni DayOfWeek kullanılır. Bu, ifadenin tüm olası giriş değerlerini işlemesini switch garanti eder. son örnek

11.3 Desen alt devamı

Switch deyiminde, bir servis talebinin deseninin önceki korumasız vaka kümesi (§13.8.3) tarafından çıkarılması hatadır. Bu, herhangi bir giriş değerinin önceki durumlardan biriyle eşleştirildiği anlamına gelir. Aşağıdaki kurallar, bir desen kümesinin belirli bir desenin ne zaman alt toplamını verdiğini tanımlar:

Bu desenin P bir desen sabitle K eşleşirP.

Bir dizi desen Q dizinini oluşturur:

  • Psabit bir desendir ve kümedeki Q desenlerden herhangi biri 'nin dönüştürülmüş değeriyle eşleşir P
  • Pbir var desenidir ve desen Q kümesi desen giriş değerinin türü (§11.1) için kapsamlıdır
  • Ptürüne T sahip bir bildirim desenidir ve desen Q kümesi tür için kapsamlıdır T (§11.4).

11.4 Desen tükenmişliği

Boş değer dışındaki her olası değer için kümedeki bir desen geçerliyse, kayıt dışı olarak bir tür için desen kümesi çok kapsamlıdır. Aşağıdaki kurallar, bir tür için bir dizi desenin ne zaman kapsamlı olduğunu tanımlar:

Aşağıdaki koşullardan herhangi biri geçerliyse, bir tür için bir dizi desen Q kapsamlıdır:T

  1. T tamsayı veya sabit listesi türü ya da bunlardan birinin null atanabilir bir sürümüdür ve 'nin null atanamaz temel türündeki Ther olası değer için içindeki bazı desenler Q bu değerle eşleşir; veya
  2. içindeki Q bazı desenler var desenidir; veya
  3. içindeki Q bazı desenler türü için bir D ve bir kimlik dönüştürmesi, örtük başvuru dönüştürmesi veya ile arasında bir kutulama dönüştürmesi TDvardır.

Örnek:

static void M(byte b)
{
    switch (b) {
        case 0: case 1: case 2: ... // handle every specific value of byte
            break;
        // error: the pattern 'byte other' is subsumed by the (exhaustive)
        // previous cases
        case byte other: 
            break;
    }
}

son örnek