Desenler (C# Başvurusu)
C#, c# 7,0 ' de model eşleştirmeyi sunmuştur. Bu tarihten sonra, her önemli C# sürümü, model eşleme yeteneklerini genişletiyor. Aşağıdaki C# ifadeleri ve deyimleri, model eşleştirmeyi destekler:
isifadesiniswitchifadeswitchifade (C# 8,0 ' de tanıtılan)
Bu yapılar içinde, bir giriş ifadesini aşağıdaki desenlerden biriyle eşleştirebilirsiniz:
- Bildirim deseninin: bir ifadenin çalışma zamanı türünü denetlemek için ve bir eşleşme başarılı olursa, belirtilen değişkene bir ifade sonucu atayın. C# 7,0 ' de kullanıma sunulmuştur.
- Bir ifadenin çalışma zamanı türünü denetlemek için tür stili:. C# 9,0 ' de kullanıma sunulmuştur.
- Sabit model: bir ifade sonucunun belirtilen bir sabit değere eşit olup olmadığını test etmek için. C# 7,0 ' de kullanıma sunulmuştur.
- İlişkisel desenler: bir ifade sonucunu belirtilen bir sabitle karşılaştırmak için. C# 9,0 ' de kullanıma sunulmuştur.
- Mantıksal desenler: bir ifadenin bir mantıksal desen bileşimiyle eşleşip eşleşmediğini test etmek. C# 9,0 ' de kullanıma sunulmuştur.
- Özellik deseni: bir ifadenin özellikleri veya alanları iç içe desenlerle eşleşiyorsa test etmek için. C# 8,0 ' de kullanıma sunulmuştur.
- Konumsal desen: bir ifade sonucunu bırakmak ve elde edilen değerler iç içe desenlerle eşleşiyorsa test etmek için. C# 8,0 ' de kullanıma sunulmuştur.
-
varmodel: herhangi bir ifadeyi eşleştirmek ve sonucunu belirtilen bir değişkene atamak için. C# 7,0 ' de kullanıma sunulmuştur. - Herhangi bir ifadeyle eşleşecek şekilde Düzenle:. C# 8,0 ' de kullanıma sunulmuştur.
Mantıksal, özellikve konumsal desenler özyinelemeli desenlerdir. Diğer bir deyişle, iç içe desenler içerebilirler.
Veri odaklı bir algoritma oluşturmak için bu desenleri nasıl kullanacağınızı gösteren örnek için bkz. öğretici: tür temelli ve veri odaklı algoritmalar oluşturmak için desen eşleştirmeyi kullanma.
Bildirim ve tür desenleri
Bir ifadenin çalışma zamanı türünün belirli bir türle uyumlu olup olmadığını denetlemek için bildirim ve tür desenleri kullanın. Bir bildirim düzeniyle yeni bir yerel değişken de bildirebilirsiniz. Bir bildirim deseninin bir ifadeyle eşleşmesi durumunda, bu değişkene, aşağıdaki örnekte gösterildiği gibi, dönüştürülmüş bir ifade sonucu atanır:
object greeting = "Hello, World!";
if (greeting is string message)
{
Console.WriteLine(message.ToLower()); // output: hello, world!
}
C# 7,0 ' den başlayarak, bir T ifade sonucu null olmadığında ve aşağıdaki koşullardan herhangi biri doğru olduğunda tür içeren bir bildirim deseninin ifadesiyle eşleşmesi gerekir:
Bir ifade sonucunun çalışma zamanı türü olur
T.Bir ifade sonucunun çalışma zamanı türü tür
T, uygulayan arabirimTveya ondan başka bir örtük başvuru dönüştürme işleminden türetilirT. Aşağıdaki örnekte, bu koşul doğru olduğunda iki durum gösterilmektedir:var 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, };Önceki örnekte, yönteme ilk çağrıda,
GetSourceLabelbağımsız değişkenin çalışma zamanı türü türünden türediğinden ilk model bir bağımsız değişken değeriyle eşleşirint[]Array . Yöntemine yapılan ikinci çağrıdaGetSourceLabel, bağımsız değişkenin çalışma zamanı türü List<T> türünden türetilmez, Array ancak ICollection<T> arabirimini uygular.Bir ifade sonucunun çalışma zamanı türü, temel alınan türe sahip null yapılabilen bir değer türüdür
T.Bir ifade sonucunun çalışma zamanı türünden tür olarak bir kutulama veya kutudan çıkarma dönüştürme var
T.
Aşağıdaki örnek, son iki koşulu göstermektedir:
int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
Console.WriteLine(a + b); // output: 30
}
Yalnızca bir ifadenin türünü denetlemek isterseniz, _ Aşağıdaki örnekte gösterildiği gibi, bir değişkenin adının yerine bir atma kullanabilirsiniz:
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)),
};
}
C# 9,0 ' den başlayarak, bu amaçla, aşağıdaki örnekte gösterildiği gibi bir tür modelini kullanabilirsiniz:
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)),
};
Bir bildirim deseninin gibi, bir ifade sonucu null olmadığında ve çalışma zamanı türü yukarıda listelenen koşullardan herhangi birini karşılıyorsa bir tür deseninin ifadesi eşleşir.
Daha fazla bilgi için, özellik teklifi notlarının bildirim düzenine ve tür deseninin bölümlerine bakın.
Sabit model
C# 7,0 ' den başlayarak, aşağıdaki örnekte gösterildiği gibi bir ifade sonucunun belirtilen bir sabit değere eşit olup olmadığını test etmek için sabit bir model kullanırsınız:
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)),
};
Sabit bir düzende, şöyle bir sabit ifade kullanabilirsiniz:
- tamsayı veya kayan nokta sayısal sabit değeri
- bir char veya dize sabit değeri
- Boole değeri
trueveyafalse - sabit listesi değeri
- Belirtilen bir const alanının veya yerel öğesinin adı
null
nullAşağıdaki örnekte gösterildiği gibi, denetlenecek sabit bir model kullanın:
if (input is null)
{
return;
}
Derleyici, ifade değerlendirildiğinde hiçbir Kullanıcı aşırı yüklenmiş eşitlik işlecinin == çağırılmasını güvence altına alır x is null .
C# 9,0 ' den başlayarak, null Aşağıdaki örnekte gösterildiği gibi, null olmayan bir sabit model kullanabilirsiniz:
if (input is not null)
{
// ...
}
Daha fazla bilgi için, özellik teklifi notunun sabit örüntüsünün bölümüne bakın.
İlişkisel desenler
C# 9,0 ' den başlayarak, aşağıdaki örnekte gösterildiği gibi bir ifade sonucunu bir sabit ile karşılaştırmak için bir ilişkisel model kullanın:
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",
};
İlişkisel bir düzende,,, veya ilişkisel işleçlerini kullanabilirsiniz < > <= >= . İlişkisel bir düzenin sağ kısmı sabit bir ifade olmalıdır. Sabit ifade bir tamsayı, kayan nokta, charveya enum türünde olabilir.
Bir ifade sonucunun belirli bir aralıkta olup olmadığını denetlemek için aşağıdaki örnekte gösterildiği gibi, bir ayırt edici and düzendeeşleştirin:
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}."),
};
Bir ifade sonucu, null null yapılabilir veya kutudan çıkarma dönüştürmesi ile bir sabit türüne dönüştürülemezse, ilişkisel bir model ifadesiyle eşleşmez.
Daha fazla bilgi için, özellik teklifi notunun ilişkisel desenler bölümüne bakın.
Mantıksal desenler
C# 9,0 ' den başlayarak, not and or aşağıdaki mantıksal desenleri oluşturmak için,, ve desenini kombinatör kullanın:
Değilleme
notbir ifade ile eşleşen, iç içe bir model ifadesiyle eşleşen kalıp. Aşağıdaki örnek, bir ifadenin null olup olmadığını denetlemek için sabit bir düzenin nasıl yapılacağını gösterirnull:if (input is not null) { // ... }Conjunyatif
andHer iki desen de ifadesiyle eşleşen bir ifadeyle eşleşen desen. Aşağıdaki örnek, bir değerin belirli bir aralıkta olup olmadığını denetlemek için ilişkisel desenleri nasıl birleştirebileceğinizi göstermektedir: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", };Ayırt edici
orAşağıdaki örnekte gösterildiği gibi desenlerden biri ifadesiyle eşleşen bir ifadeyle eşleşen desen: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}."), };
Yukarıdaki örnekte gösterildiği gibi, Kombinatör deseninin bir düzende tekrar tekrar kullanabilirsiniz.
andCombinator deseninin önceliği daha yüksektir or . Önceliği açıkça belirtmek için aşağıdaki örnekte gösterildiği gibi ayraçları kullanın:
static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');
Not
Desenlerin denetlenme sırası tanımsız. Çalışma zamanında, ve desenlerinin sağ iç içe geçmiş desenleri or and önce denetlenebilir.
Daha fazla bilgi için, özellik teklifi notunun örüntüsünün kombinatör bölümüne bakın.
Özellik kalıbı
C# 8,0 ' den başlayarak, aşağıdaki örnekte gösterildiği gibi bir ifadenin özelliklerini veya alanlarını iç içe desenlerle eşleştirmek için bir özellik deseni kullanın:
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
Bir ifade sonucu null olmadığında ve tüm iç içe desenler ifade sonucunun karşılık gelen özelliği veya alanıyla eşleştiğinde bir özellik deseninin ifadesiyle eşleşir.
Aşağıdaki örnekte gösterildiği gibi, bir özellik düzenine bir çalışma zamanı tür denetimi ve değişken bildirimi de ekleyebilirsiniz:
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."),
};
Özellik deseninin özyinelemeli bir deseninin olması. Diğer bir deyişle, herhangi bir kalıbı iç içe geçmiş bir model olarak kullanabilirsiniz. Aşağıdaki örnekte gösterildiği gibi, veri parçalarını iç içe geçmiş desenlere göre eşleştirmek için bir özellik deseni kullanın:
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 } };
Yukarıdaki örnek C# 9,0 ve üzeri sürümlerde kullanılabilen iki özelliği kullanır: or örüncombinator ve kayıt türleri.
C# 10 ' dan başlayarak, bir özellik deseninin içinde iç içe özelliklere veya alanlara başvurabilirsiniz. Örneğin, önceki örnekteki yöntemi aşağıdaki eşdeğer koda yeniden düzenleyebilirsiniz:
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start.Y: 0 } or { End.Y: 0 };
Daha fazla bilgi için, özellik teklifi notunun özellik düzeni bölümüne ve genişletilmiş özellik desenleri Özellik teklifi notuna bakın.
Konumsal model
C# 8,0 ' den başlayarak, bir ifade sonucunu bırakmak ve elde edilen değerleri, aşağıdaki örnekte gösterildiği gibi, iç içe geçmiş desenlerle eşleştirmek için bir konumsal düzen kullanın:
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",
};
Önceki örnekte, bir ifadenin türü bir ifade sonucunu bırakmak için kullanılan deyapýsý metodunu içerir. Ayrıca, konumsal desenlerde demet türleri ifadelerini de eşleştirebilirsiniz. Bu şekilde, aşağıdaki örnekte gösterildiği gibi çeşitli modellerdeki birden çok girişi eşleştirebilirsiniz:
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,
};
Önceki örnekte, C# 9,0 ve üzeri sürümlerde kullanılabilen ilişkisel ve mantıksal desenler kullanılmaktadır.
DeconstructAşağıdaki örnekte gösterildiği gibi, konumsal bir düzende demet öğelerinin ve parametrelerinin adlarını kullanabilirsiniz:
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);
}
Ayrıca, konum düzenlerini aşağıdaki yollarla genişletebilirsiniz:
Aşağıdaki örnekte olduğu gibi bir çalışma zamanı türü denetimi ve değişken bildirimi ekleyin:
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, };Yukarıdaki örnek, yöntemini örtülü olarak sağlayan konumsal kayıtları
Deconstructkullanır.Aşağıdaki örnekte de olduğu gibi konumsal desen içinde bir özellik deseni kullanın:
public record WeightedPoint(int X, int Y) { public double Weight { get; set; } } static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };Aşağıdaki örnekte de olduğu gibi önceki iki kullanımı birleştirin:
if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p) { // .. }
Konumsal desen,cursive desendir. Başka bir ifadeyle, herhangi bir deseni iç içe geçmiş desen olarak kullanabilirsiniz.
Daha fazla bilgi için özellik teklifi notun Konumsal düzen bölümüne bakın.
var Desen
C# 7.0'dan itibaren, var dahil olmak üzere herhangi bir ifadeyle eşleşmek için bir desen kullanır ve aşağıdaki örnekte de olduğu gibi sonucu yeni bir yerel null değişkene atarsiniz:
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();
}
Bir var desen, ara hesaplamaların sonucu tutmak için Boole ifadesinde geçici bir değişkene ihtiyacınız olduğunda kullanışlıdır. Aşağıdaki örnekte de olduğu gibi bir ifadenin veya deyimin korumaları durumunda ek denetimler gerçekleştirmeniz gereken var when bir desen de switch kullanabilirsiniz:
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 }
}
Yukarıdaki örnekte desen, var (x, y) konumsal desene eşdeğerdir. (var x, var y)
Bir var desende, bildirilen bir değişkenin türü, desenle eşlenmiş ifadenin derleme zamanı t t t'dır.
Daha fazla bilgi için özellik teklifi notun Var deseni bölümüne bakın.
Atma düzeni
C# 8.0'dan itibaren, aşağıdaki örnekte de olduğu gibi dahil olmak üzere herhangi bir ifadeyle eşleşmek _ için bir atma deseni null kullanırsiniz:
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,
};
Yukarıdaki örnekte, bir atma deseni ve numaralama karşılık gelen üyesi olmayan herhangi bir tamsayı değerini işlemek null DayOfWeek için kullanılır. Bu, örnekteki bir switch ifadenin tüm olası giriş değerlerini işlemesini garanti eder. Bir ifadede atma deseni kullanmayacaksanız ve ifadenin desenlerinin hiçbiri bir girişle eşleşmezse, switch çalışma zamanı bir özel durum oluşturur. Bir ifade tüm olası giriş değerlerini switch işlemezse derleyici bir uyarı üretir.
Atma deseni bir ifadede veya is deyimde desen switch olamaz. Böyle durumlarda, herhangi bir ifadeyle eşleşmek için atma var ile bir desen kullanın: var _ .
Daha fazla bilgi için özellik teklifi notun Atma düzeni bölümüne bakın.
Parantezli desen
C# 9.0'dan itibaren, herhangi bir desenin çevreye parantez koyarak. Genellikle, aşağıdaki örnekte olduğu gibi mantıksal desenlerde önceliği vurgulamakveya değiştirmek için bunu yapabilirsiniz:
if (input is not (float or double))
{
return;
}
C# dili belirtimi
Daha fazla bilgi için aşağıdaki özellik teklifi notlarına bakın:
- C# 7.0 için desen eşleştirme
- Recursive desen eşleştirmesi (C# 8.0'da tanıtıldı)
- C# 9.0 için desen eşleştirme değişiklikleri
- Genişletilmiş özellik desenleri (C# 10)