Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Pencocokan pola -
is Gunakan ekspresi, pernyataan pengalihan, dan ekspresi pengalihan untuk mencocokkan ekspresi input dengan sejumlah karakteristik. C# mendukung beberapa pola, termasuk deklarasi, jenis, konstanta, relasional, properti, daftar, var, dan buang. Anda dapat menggabungkan pola dengan menggunakan kata kunci andlogika Boolean , , ordan not.
Referensi bahasa C# mendokumentasikan versi bahasa C# yang paling baru dirilis. Ini juga berisi dokumentasi awal untuk fitur dalam pratinjau publik untuk rilis bahasa yang akan datang.
Dokumentasi mengidentifikasi fitur apa pun yang pertama kali diperkenalkan dalam tiga versi terakhir bahasa atau dalam pratinjau publik saat ini.
Petunjuk / Saran
Untuk menemukan kapan fitur pertama kali diperkenalkan di C#, lihat artikel tentang riwayat versi bahasa C#.
Ekspresi dan pernyataan C# berikut mendukung pencocokan pola:
Dalam konstruksi tersebut, Anda dapat mencocokkan ekspresi input dengan salah satu pola berikut:
- Pola deklarasi: periksa jenis run-time ekspresi dan, jika kecocokan berhasil, tetapkan hasil ekspresi ke variabel yang dideklarasikan.
- Pola tipe: periksa tipe run-time dari ekspresi.
- Pola konstanta: uji bahwa hasil ekspresi sama dengan konstanta tertentu.
- Pola relasional: membandingkan hasil ekspresi dengan konstanta tertentu.
- Pola logis: uji bahwa ekspresi cocok dengan kombinasi pola logis.
- Pola properti: uji bahwa properti atau bidang ekspresi cocok dengan pola berlapis.
- Pola posisi: mendekonstruksi hasil ekspresi dan menguji apakah nilai yang dihasilkan cocok dengan pola berlapis.
-
varpola: cocokkan ekspresi apa pun dan tetapkan hasilnya ke variabel yang dideklarasikan. - Buang pola: cocok dengan ekspresi apa pun.
- Pola daftar: uji bahwa urutan elemen cocok dengan pola berlapis yang sesuai.
Pola logis, properti, posisi, dan daftar adalah pola rekursif . Artinya, pola tersebut dapat berisi pola bersarang.
Untuk contoh cara menggunakan pola tersebut untuk membangun algoritma berbasis data, lihat Tutorial: Menggunakan pencocokan pola untuk membangun algoritma berbasis jenis dan berbasis data.
Deklarasi dan pola jenis
Gunakan pola deklarasi dan jenis untuk memeriksa apakah jenis run-time ekspresi kompatibel dengan jenis tertentu. Dengan menggunakan pola deklarasi, Anda juga dapat mendeklarasikan variabel lokal baru. Saat pola deklarasi cocok dengan ekspresi, pola tersebut menetapkan variabel ke hasil ekspresi yang dikonversi, seperti yang ditunjukkan contoh berikut:
object greeting = "Hello, World!";
if (greeting is string message)
{
Console.WriteLine(message.ToLower()); // output: hello, world!
}
Pola deklarasi dengan jenis T cocok dengan ekspresi saat hasil ekspresi non-null dan salah satu kondisi berikut ini benar:
- Tipe run-time dari hasil ekspresi memiliki konversi identitas ke
T. - Jenisnya
Tadalahref structjenis dan ada konversi identitas dari ekspresi keT. - Jenis run-time dari hasil ekspresi berasal dari jenis
T, mengimplementasikan antarmukaT, atau konversi referensi implisit lainya yang sudah ada darinya keT. Kondisi ini mencakup hubungan warisan dan implementasi antarmuka. Contoh berikut menunjukkan dua kasus ketika kondisi ini benar:
Dalam contoh sebelumnya, pada panggilan pertama ke metodevar numbers = new int[] { 10, 20, 30 }; Console.WriteLine(GetSourceLabel(numbers)); // output: 1 var letters = new List<char> { 'a', 'b', 'c', 'd' }; Console.WriteLine(GetSourceLabel(letters)); // output: 2 static int GetSourceLabel<T>(IEnumerable<T> source) => source switch { Array array => 1, ICollection<T> collection => 2, _ => 3, };GetSourceLabel, pola pertama cocok dengan nilai argumen karena tipe run-time argumenint[]berasal dari jenis Array. Pada panggilan kedua ke metodeGetSourceLabel, jenis run-time argumen List<T> tidak diturunkan dari jenis Array, tetapi mengimplementasikan antarmuka ICollection<T>. - Jenis run-time dari hasil ekspresi adalah tipe nilai nullable dengan tipe yang mendasarinya dan
Tadalah Nullable<T>.HasValue. - Konversi penyematan atau pembongkaran merupakan dari tipe run-time hasil ekspresi ke tipe
Tketika ekspresi bukan instance dariref struct.
Pola deklarasi tidak mempertimbangkan konversi yang ditentukan pengguna atau konversi rentang implisit.
Contoh berikut menunjukkan dua kondisi terakhir:
int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
Console.WriteLine(a + b); // output: 30
}
Untuk memeriksa hanya jenis ekspresi, gunakan buang _ sebagai pengganti nama variabel, seperti yang ditunjukkan contoh berikut:
public abstract class Vehicle {}
public class Car : Vehicle {}
public class Truck : Vehicle {}
public static class TollCalculator
{
public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
Car _ => 2.00m,
Truck _ => 7.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
}
Untuk tujuan tersebut, gunakan pola jenis, seperti yang ditunjukkan contoh berikut:
public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
Car => 2.00m,
Truck => 7.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
Seperti pola deklarasi, pola jenis cocok dengan ekspresi ketika hasil ekspresi non-null dan jenis run-time-nya memenuhi salah satu kondisi sebelumnya.
Untuk memeriksa non-null, gunakanpola konstanta yang null, seperti yang ditunjukkan contoh berikut:
if (input is not null)
{
// ...
}
Untuk informasi selengkapnya, lihat bagian Pola deklarasi dan Pola jenis dari spesifikasi bahasa C#.
Pola konstanta
Pola konstanta adalah sintaks alternatif untuk == ketika operand di sebelah kanan adalah konstanta. Gunakan pola konstanta untuk menguji apakah hasil ekspresi sama dengan konstanta tertentu, seperti yang ditunjukkan contoh berikut:
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
1 => 12.0m,
2 => 20.0m,
3 => 27.0m,
4 => 32.0m,
0 => 0.0m,
_ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
Dalam pola konstanta, Anda dapat menggunakan ekspresi konstanta apa pun, seperti:
- literal numerik integer atau floating-point
- char
- untai (karakter) literal
- nilai Boolean
trueataufalse - nilai enum
- nama bidang const yang dideklarasikan atau lokal
null
Ekspresi harus berupa jenis yang dapat dikonversi ke jenis konstanta, dengan satu pengecualian: Ekspresi yang jenisnya Span<char> atau ReadOnlySpan<char> dapat dicocokkan dengan string konstanta.
Gunakan pola konstan untuk memeriksa null, seperti yang ditunjukkan contoh berikut:
if (input is null)
{
return;
}
Kompilator menjamin bahwa ia tidak memanggil operator == kesetaraan yang kelebihan beban pengguna saat mengevaluasi ekspresi x is null.
Anda dapat menggunakan pola konstanta yang dinegasikannull untuk memeriksa non-null, seperti yang ditunjukkan contoh berikut:
if (input is not null)
{
// ...
}
Untuk informasi lebih lanjut, lihat bagian Pola konstanta dari catatan proposal fitur.
Pola relasional
Gunakan pola relasional untuk membandingkan hasil ekspresi dengan konstanta, seperti yang ditunjukkan contoh berikut:
Console.WriteLine(Classify(13)); // output: Too high
Console.WriteLine(Classify(double.NaN)); // output: Unknown
Console.WriteLine(Classify(2.4)); // output: Acceptable
static string Classify(double measurement) => measurement switch
{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};
Dalam pola relasional, gunakan salah satu operator <, , >, <=atau >=. Bagian kanan dari pola relasional harus berupa ekspresi konstanta. Ekspresi konstanta dapat berupa integer, floating-point, char, atau enum.
Untuk memeriksa apakah hasil ekspresi berada dalam rentang tertentu, cocokkan dengan pola andkonjungtif, seperti yang ditunjukkan contoh berikut:
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 3, 14))); // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 7, 19))); // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 2, 17))); // output: winter
static string GetCalendarSeason(DateTime date) => date.Month switch
{
>= 3 and < 6 => "spring",
>= 6 and < 9 => "summer",
>= 9 and < 12 => "autumn",
12 or (>= 1 and < 3) => "winter",
_ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};
Jika hasil ekspresi adalah null atau gagal mengonversi ke jenis konstanta dengan menggunakan konversi nullable atau unboxing, pola relasional tidak cocok dengan ekspresi.
Untuk informasi selengkapnya, lihat bagian Pola relasional dari spesifikasi bahasa C#.
Pola logika
notGunakan combinator pola , and, dan or untuk membuat pola logis berikut:
Pola negasi
notyang cocok dengan ekspresi saat pola yang dinegasikan tidak cocok dengan ekspresi. Contoh berikut menunjukkan bagaimana Anda dapat meniadakan pola konstantanulluntuk memeriksa apakah ekspresi bukan null:if (input is not null) { // ... }Pola konjunctif
andyang cocok dengan ekspresi saat kedua pola cocok dengan ekspresi. Contoh berikut menunjukkan bagaimana Anda dapat menggabungkan pola relasional untuk memeriksa apakah suatu nilai berada dalam rentang tertentu:Console.WriteLine(Classify(13)); // output: High Console.WriteLine(Classify(-100)); // output: Too low Console.WriteLine(Classify(5.7)); // output: Acceptable static string Classify(double measurement) => measurement switch { < -40.0 => "Too low", >= -40.0 and < 0 => "Low", >= 0 and < 10.0 => "Acceptable", >= 10.0 and < 20.0 => "High", >= 20.0 => "Too high", double.NaN => "Unknown", };Pola disjunctive
oryang cocok dengan ekspresi saat salah satu pola cocok dengan ekspresi, seperti yang ditunjukkan contoh berikut:Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19))); // output: winter Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9))); // output: autumn Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11))); // output: spring static string GetCalendarSeason(DateTime date) => date.Month switch { 3 or 4 or 5 => "spring", 6 or 7 or 8 => "summer", 9 or 10 or 11 => "autumn", 12 or 1 or 2 => "winter", _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."), };
Seperti yang ditunjukkan contoh sebelumnya, Anda dapat menggunakan combinator pola berulang kali dalam pola.
Prioritas dan urutan pemeriksaan
Combinator pola memeriksa ekspresi dalam urutan ini, berdasarkan urutan ekspresi pengikatan:
notandor
Pola not mengikat ke operand-nya terlebih dahulu. Pola and mengikat setelah pengikatan ekspresi pola apa pun not . Pola mengikat or setelah semua not dan and pola mengikat operand. Contoh berikut mencoba mencocokkan semua karakter yang bukan huruf kecil, a melalui z. Ini memiliki kesalahan, karena pola mengikat not sebelum and pola:
// Incorrect pattern. `not` binds before `and`
static bool IsNotLowerCaseLetter(char c) => c is not >= 'a' and <= 'z';
Pengikatan default berarti contoh sebelumnya diurai sebagai contoh berikut:
// The default binding without parentheses is shows in this method. `not` binds before `and`
static bool IsNotLowerCaseLetterDefaultBinding(char c) => c is ((not >= 'a') and <= 'z');
Untuk memperbaiki kesalahan, tentukan bahwa Anda ingin pola mengikat not ekspresi >= 'a' and <= 'z' :
// Correct pattern. Force `and` before `not`
static bool IsNotLowerCaseLetterParentheses(char c) => c is not (>= 'a' and <= 'z');
Menambahkan tanda kurung menjadi lebih penting karena pola Anda menjadi lebih rumit. Secara umum, gunakan tanda kurung untuk mengklarifikasi pola Anda untuk pengembang lain, seperti yang ditunjukkan contoh berikut:
static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');
Catatan
Urutan di mana kompilator memeriksa pola yang memiliki urutan pengikatan yang sama tidak terdefinisi. Pada waktu proses, pengkompilasi dapat memeriksa pola berlapis kanan dari beberapa or pola dan beberapa and pola terlebih dahulu.
Untuk informasi selengkapnya, lihat bagian Combinator pola dari spesifikasi bahasa C#.
Pola properti
Gunakan pola properti untuk mencocokkan properti atau bidang ekspresi dengan pola berlapis, seperti yang ditunjukkan contoh berikut:
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
Pola properti cocok dengan ekspresi saat hasil ekspresi non-null dan setiap pola berlapis cocok dengan properti atau bidang yang sesuai dari hasil ekspresi.
Anda dapat menambahkan pemeriksaan jenis run-time dan deklarasi variabel ke pola properti, seperti yang ditunjukkan contoh berikut:
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."),
};
Konstruksi ini secara khusus berarti bahwa pola properti is { } cocok dengan semuanya non-null, dan Anda dapat menggunakannya alih-alih is not null membuat variabel: somethingPossiblyNull is { } somethingDefinitelyNotNull.
if (GetSomeNullableStringValue() is { } nonNullValue) // Empty property pattern with variable creation
{
Console.WriteLine("NotNull:" + nonNullValue);
}
else
{
nonNullValue = "NullFallback"; // we can access the variable here.
Console.WriteLine("it was null, here's the fallback: " + nonNullValue);
}
Pola properti adalah pola rekursif. Anda dapat menggunakan pola apa pun sebagai pola berlapis. Gunakan pola properti untuk mencocokkan bagian data dengan pola bersarang, seperti yang ditunjukkan contoh berikut:
public record Point(int X, int Y);
public record Segment(Point Start, Point End);
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start: { Y: 0 } } or { End: { Y: 0 } };
Contoh sebelumnya menggunakan orcombinator pola dan jenis rekaman.
Anda dapat mereferensikan properti atau bidang berlapis dalam pola properti. Kemampuan ini dikenal sebagai pola properti yang diperluas. Misalnya, Anda dapat merefaktor metode dari contoh sebelumnya ke dalam kode yang setara berikut:
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start.Y: 0 } or { End.Y: 0 };
Untuk informasi selengkapnya, lihat bagian Pola properti dari standar C#.
Petunjuk / Saran
Untuk meningkatkan keterbacaan kode, gunakan aturan gaya Sederhanakan pola properti (IDE0170). Ini menyarankan tempat untuk menggunakan pola properti yang diperluas.
Pola posisional
Gunakan pola posisional untuk mendekonstruksi ekspresi dan mencocokkan nilai yang dihasilkan dengan pola berlapis yang sesuai, seperti yang ditunjukkan contoh berikut:
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);
}
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",
};
Dalam contoh sebelumnya, jenis ekspresi berisi metode Dekonstruksi , yang digunakan pola untuk mendekonstruksi hasil ekspresi.
Penting
Urutan anggota dalam pola posisi harus cocok dengan urutan parameter dalam Deconstruct metode . Kode yang dihasilkan untuk pola posisi memanggil Deconstruct metode .
Anda juga dapat mencocokkan ekspresi jenis tuple dengan pola posisi. Dengan menggunakan pendekatan ini, Anda dapat mencocokkan beberapa input dengan berbagai pola, seperti yang ditunjukkan contoh berikut:
static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)
=> (groupSize, visitDate.DayOfWeek) switch
{
(<= 0, _) => throw new ArgumentException("Group size must be positive."),
(_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,
(>= 5 and < 10, DayOfWeek.Monday) => 20.0m,
(>= 10, DayOfWeek.Monday) => 30.0m,
(>= 5 and < 10, _) => 12.0m,
(>= 10, _) => 15.0m,
_ => 0.0m,
};
Contoh sebelumnya menggunakan pola relasional dan logis .
Anda dapat menggunakan nama elemen tuple dan parameter Deconstruct dalam pola posisional, seperti yang ditunjukkan contoh berikut:
var numbers = new List<int> { 1, 2, 3 };
if (SumAndCount(numbers) is (Sum: var sum, Count: > 0))
{
Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}"); // output: Sum of [1 2 3] is 6
}
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);
}
Anda juga dapat memperluas pola posisi dengan salah satu cara berikut:
Tambahkan pemeriksaan jenis run-time dan deklarasi variabel, seperti yang ditunjukkan contoh berikut:
public record Point2D(int X, int Y); public record Point3D(int X, int Y, int Z); static string PrintIfAllCoordinatesArePositive(object point) => point switch { Point2D (> 0, > 0) p => p.ToString(), Point3D (> 0, > 0, > 0) p => p.ToString(), _ => string.Empty, };Contoh sebelumnya menggunakan rekaman posisional yang secara implisit menyediakan metode
Deconstruct.Gunakan pola properti dalam pola posisional, seperti yang ditunjukkan contoh berikut:
public record WeightedPoint(int X, int Y) { public double Weight { get; set; } } static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };Gabungkan dua penggunaan sebelumnya, seperti yang ditunjukkan contoh berikut:
if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p) { // .. }
Pola posisional adalah pola rekursif. Artinya, Anda dapat menggunakan pola apa pun sebagai pola bersarang.
Untuk informasi lebih lanjut, lihat bagian Pola posisional dari catatan proposal fitur.
Pola var
var Gunakan pola untuk mencocokkan ekspresi apa pun, termasuk null, dan tetapkan hasilnya ke variabel lokal baru, seperti yang ditunjukkan contoh berikut:
static bool IsAcceptable(int id, int absLimit) =>
SimulateDataFetch(id) is var results
&& results.Min() >= -absLimit
&& results.Max() <= absLimit;
static int[] SimulateDataFetch(int id)
{
var rand = new Random();
return Enumerable
.Range(start: 0, count: 5)
.Select(s => rand.Next(minValue: -10, maxValue: 11))
.ToArray();
}
Pola var berguna saat Anda membutuhkan variabel sementara dalam ekspresi Boolean untuk menampung hasil penghitungan perantara. Anda juga dapat menggunakan var pola saat Anda perlu melakukan lebih banyak pemeriksaan jika terjadi penjaga when ekspresi atau pernyataan, seperti yang ditunjukkan switch contoh berikut:
public record Point(int X, int Y);
static Point Transform(Point point) => point switch
{
var (x, y) when x < y => new Point(-x, y),
var (x, y) when x > y => new Point(x, -y),
var (x, y) => new Point(x, y),
};
static void TestTransform()
{
Console.WriteLine(Transform(new Point(1, 2))); // output: Point { X = -1, Y = 2 }
Console.WriteLine(Transform(new Point(5, 2))); // output: Point { X = 5, Y = -2 }
}
Dalam contoh sebelumnya, pola var (x, y) setara dengan pola(var x, var y)posisi .
var Dalam pola, jenis variabel yang dideklarasikan adalah jenis waktu kompilasi ekspresi yang cocok dengan pola.
Untuk informasi lebih lanjut, lihat bagian pola Var dari catatan proposal fitur.
Pola buang
Gunakan pola _ untuk mencocokkan ekspresi apa pun, termasuk null, seperti yang ditunjukkan contoh berikut:
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)); // output: 5.0
Console.WriteLine(GetDiscountInPercent(null)); // output: 0.0
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10)); // output: 0.0
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,
};
Dalam contoh sebelumnya, gagang null pola buang dan nilai bilangan bulat apa pun yang tidak memiliki anggota DayOfWeek enumerasi yang sesuai. Jaminan itu memastikan bahwa switch ekspresi dalam contoh menangani semua kemungkinan nilai input. Jika Anda tidak menggunakan pola buang dalam ekspresi switch dan tidak ada pola ekspresi yang cocok dengan input, waktu proses melempar pengecualian. Pengompilasi menghasilkan peringatan jika ekspresi switch tidak menangani semua kemungkinan nilai input.
Pola buang tidak boleh berupa pola dalam ekspresi is atau pernyataan switch. Dalam kasus tersebut, untuk mencocokkan ekspresi apa pun, gunakan pola var dengan membuang: var _. Pola buang bisa menjadi pola dalam switch ekspresi.
Untuk informasi lebih lanjut, lihat bagian Pola Buang dari catatan proposal fitur.
Pola tanda kurung
Anda dapat menempatkan tanda kurung di sekitar pola apa pun. Biasanya, Anda melakukan ini untuk menekankan atau mengubah prioritas dalam pola logis, seperti yang ditunjukkan contoh berikut:
if (input is not (float or double))
{
return;
}
Pola daftar
Anda dapat mencocokkan array atau daftar dengan urutan pola, seperti yang ditunjukkan contoh berikut:
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
Console.WriteLine(numbers is [1, 2, 3, 4]); // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // True
Seperti yang ditunjukkan contoh sebelumnya, pola daftar cocok ketika setiap pola berlapis cocok dengan elemen yang sesuai dari urutan input. Anda dapat menggunakan pola apa pun dalam pola daftar. Untuk mencocokkan elemen apa pun, gunakan pola buang atau, jika Anda juga ingin mengambil elemen, gunakan pola var, seperti yang ditunjukkan contoh berikut:
List<int> numbers = new() { 1, 2, 3 };
if (numbers is [var first, _, _])
{
Console.WriteLine($"The first element of a three-item list is {first}.");
}
// Output:
// The first element of a three-item list is 1.
Contoh sebelumnya cocok dengan seluruh urutan input terhadap pola daftar. Untuk mencocokkan elemen hanya di awal atau akhir - atau keduanya - dari urutan input, gunakan pola .., seperti yang ditunjukkan contoh berikut:
Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]); // True
Console.WriteLine(new[] { 1, 1 } is [_, _, ..]); // True
Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]); // False
Console.WriteLine(new[] { 1 } is [1, 2, ..]); // False
Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]); // True
Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]); // False
Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]); // True
Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]); // True
Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]); // True
Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]); // False
Pola ilis cocok dengan nol atau lebih elemen. Anda dapat menggunakan paling banyak satu pola ilis dalam pola daftar. Pola ilis hanya dapat muncul dalam pola daftar.
Anda juga dapat menumpuk subpattern dalam pola ipotong, seperti yang ditunjukkan contoh berikut:
void MatchMessage(string message)
{
var result = message is ['a' or 'A', .. var s, 'a' or 'A']
? $"Message {message} matches; inner part is {s}."
: $"Message {message} doesn't match.";
Console.WriteLine(result);
}
MatchMessage("aBBA"); // output: Message aBBA matches; inner part is BB.
MatchMessage("apron"); // output: Message apron doesn't match.
void Validate(int[] numbers)
{
var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";
Console.WriteLine(result);
}
Validate(new[] { -1, 0, 1 }); // output: not valid
Validate(new[] { -1, 0, 0, 1 }); // output: valid
Untuk informasi selengkapnya, lihat Mencantumkan pola dalam spesifikasi bahasa C#.
Pola hierarki tertutup
Mulai C# 15, switch ekspresi yang jenis tata kelolanya adalah closedkelas lengkap ketika lengannya menangani setiap turunan langsung dari kelas itu. Pengkompilasi tidak memerlukan lengan default karena sakelarnya lengkap:
public closed record class PaymentMethod;
public record class Cash : PaymentMethod;
public record class Card(string Last4) : PaymentMethod;
public record class BankTransfer(string Iban) : PaymentMethod;
public static string Describe(PaymentMethod method) => method switch
{
Cash => "cash",
Card(var last4) => $"card ending {last4}",
BankTransfer(var iban) => $"bank transfer to {iban}",
// No warning: every direct descendant of 'PaymentMethod' is handled.
};
Sakelar hierarki tertutup hanya lengkap ketika setiap turunan langsung dapat dijangkau dari lokasi sakelar. Jika turunan langsung kurang dapat diakses daripada jenis dasar tertutup dan tidak terlihat di situs switch, kompilator memperlakukannya sebagai tidak tertangani dan memperingatkan bahwa sakelar tidak lengkap.
Misalnya, kelas dasar tertutup public dapat memiliki internal keturunan langsung. Kode dalam rakitan yang sama melihat set lengkap turunan, tetapi kode di rakitan lain tidak:
// Assembly 1
public closed record class Shape;
public record class Circle(double Radius) : Shape;
internal record class Triangle(double Base, double Height) : Shape;
// Same assembly: 'Triangle' is visible, so the switch is exhaustive.
internal static double Area(Shape shape) => shape switch
{
Circle(var r) => Math.PI * r * r,
Triangle(var b, var h) => 0.5 * b * h,
};
// Assembly 2
public static string Name(Shape shape) => shape switch
{
Circle => "circle",
// Warning CS8509: the switch expression doesn't handle all possible values.
// 'Triangle' is a direct descendant of 'Shape' but isn't visible here.
};
Untuk memulihkan kelelahan di rakitan 2, tambahkan lengan buang (_ => ...), tambahkan lengan kelas dasar (Shape dalam contoh sebelumnya), atau buat setiap turunan langsung setidaknya dapat diakses sebagai jenis dasar tertutup.
Ketika jenis tata kelola dapat diubah ke null, null adalah nilai tambahan yang harus ditangani sakelar. Switch over PaymentMethod? yang menghilangkan null lengan tidak lengkap bahkan ketika setiap turunan langsung dicocokkan.
Turunan dari kelas tertutup tidak transitif: turunan tidak tertutup dari kelas tertutup dapat berasal dari rakitan lain. Kompilator hanya memperlakukan turunan langsung sebagai set lengkap. Untuk beralih ke keturunan juga mendapat manfaat dari pemeriksaan kelelahan, nyatakan turunan closed (atau sealed).
Karena turunan tidak langsung tidak memperluas set lengkap basis tertutup, Anda tidak perlu menambahkan lengan untuk setiap subjenis transitif untuk memenuhi kelelahan. Subsumption antara lengan masih berfungsi dengan cara yang sama seperti untuk hierarki kelas apa pun: lengan yang cocok dengan jenis dasar mencakup setiap subjenis, dan lengan selanjutnya yang cocok dengan salah satu subtipe tersebut tidak dapat dijangkau. Pertimbangkan tertutup Vehicle yang keturunan langsungnya adalah Car dan Truck, ditambah turunan Sedan tidak langsung yang dideklarasikan di rakitan lain:
// Assembly 1
public closed record class Vehicle;
public record class Car(int Doors) : Vehicle;
public record class Truck(double PayloadTons) : Vehicle;
// Assembly 2
public record class Sedan(int Doors) : Car(Doors);
Switch over Vehicle lengkap setelah menangani Car dan Truck, meskipun Sedan ada. Lengan Car mencakup setiap Sedan nilai:
public static string Category(Vehicle v) => v switch
{
Car => "car",
Truck => "truck",
// No warning. The 'Car' arm covers 'Sedan' through ordinary subtype matching.
};
Untuk mengirimkan secara Sedan khusus, letakkan lengannya di depanCar lengan. Lengan Car tetap dapat dijangkau karena masih cocok dengan setiap Car yang bukan Sedan:
public static string CategorySedanFirst(Vehicle v) => v switch
{
Sedan => "sedan",
Car => "car", // Reachable: 'Car' values that aren't 'Sedan'.
Truck => "truck",
};
Membalikkan kedua lengan tersebut menghasilkan kesalahan subsumption, seperti halnya dalam hierarki kelas lainnya. Pengkompilasi mendeteksi bahwa Car lengan sudah mencakup Sedan:
string Category(Vehicle v) => v switch
{
Car => "car",
Sedan => "sedan", // Error CS8510: the pattern is unreachable. It has already been handled by 'Car => ...'.
Truck => "truck",
};
Jika Anda ingin kelelahan untuk mengikuti hierarki lebih jauh ke bawah, nyatakan Car dirinya closed. Kompilator kemudian memperlakukan setiap keturunan Car langsung (seperti ) seperti Sedanset lengkap yang berakar pada Car. Sakelar yang jenis Car tata kelolanya lengkap ketika melakukan salah satu hal berikut:
- Menangani setiap keturunan
Carlangsung dengan lengannya sendiri. -
CarTermasuk lengan, yang mencakup setiapCarnilai (termasuk semua subjenis). - Termasuk lengan buang (
_ => ...) atau lengan untuk jenisCardasar , sepertiVehicle.
Sakelar yang jenis tata kelolanya Vehicle memiliki pilihan: Kode yang menangani Car dan Truck masih lengkap, karena Car lengan mencakup setiap subjenis Car. Menandai Carclosed hanya memberi Anda opsi kedua untuk sakelar tersebut. Anda dapat menyimpan lengan tunggal Car , atau menggantinya dengan satu lengan per turunan Car langsung (bersama Truck lengan) dan masih lengkap.
Penandaan Carclosed juga membuatnya secara abstractimplisit , yang berarti Anda tidak dapat lagi membuat instans secara Car langsung. Itu mungkin tidak sesuai dengan desain Anda. Jika Anda perlu Car tetap instans, biarkan terbuka dan kirim pada subjenis tertentu yang Anda pedulikan dengan memesan lengan seperti yang ditunjukkan sebelumnya.
Jenis tata kelola parameter jenis
Ekspresi switch yang jenis tata kelolanya adalah parameter jenis yang dibatasi ke kelas tertutup habis pada istilah yang sama dengan sakelar di atas kelas tertutup itu sendiri. Untuk mengirimkan hierarki tertutup dari kode generik, batasi parameter jenis ke basis tertutup dan tangani setiap turunan langsung:
public static string Describe<X>(X method) where X : PaymentMethod => method switch
{
Cash => "cash",
Card(var last4) => $"card ending {last4}",
BankTransfer(var iban) => $"bank transfer to {iban}",
// No warning: 'X' is constrained to the closed type 'PaymentMethod',
// so handling every direct descendant exhausts the switch.
};
Untuk informasi selengkapnya, lihat pengubah tertutup. Untuk spesifikasinya, lihat Hierarki tertutup.
Pola gabungan
Dimulai dengan C# 15, ketika nilai masuk pola adalah jenis gabungan, pola secara otomatis membongkar union. Mereka berlaku untuk properti serikat Value , bukan nilai serikat itu sendiri. Perilaku ini membuat penyatuan transparan terhadap pencocokan pola:
public record class Cat(string Name);
public record class Dog(string Name);
public union Pet(Cat, Dog);
string Describe(Pet pet) => pet switch
{
Dog d => d.Name,
Cat c => c.Name,
};
Dua pola adalah pengecualian: var pola dan pola buang _ berlaku untuk nilai serikat itu sendiri, bukan propertinya Value .
Pola null memeriksa apakah serikat tidak Value ada. Untuk serikat berbasis kelas, null juga berhasil ketika referensi serikat itu sendiri null.
Ketika jenis serikat menyediakan pola akses non-tinju (HasValue dan TryGetValue anggota), pengkompilasi menggunakan anggota tersebut untuk menghindari kasus jenis nilai tinju selama pencocokan pola.
Untuk informasi selengkapnya, lihat Pencocokan union. Untuk spesifikasinya, lihat Unions.
Spesifikasi bahasa C#
Untuk informasi selengkapnya, lihat bagian Pola dan pencocokan pola dari spesifikasi bahasa C#, termasuk: