跳過到頁腳內容
.NET幫助

C# 模式匹配表達式(對於開發者的運行原理)

C# 中的模式匹配是 C# 7.0 中引入的一項強大功能,並在之後的版本中不斷擴展。 它讓開發人員在處理條件語句、類型檢查和物件解構時,能寫出更簡潔且更具表達力的程式碼。

模式匹配表達式提供了一種靈活直觀的方式,將值與模式進行匹配,並執行相應的程式碼區塊。 在本文中,我們將探討 C# 中模式匹配表達式的複雜性,包括語法、使用案例和程式碼範例。 在文章的最後,我們還將探討一下 Iron SoftwareIronPDF PDF 生成函式庫,以便在 C# 應用程式中快速生成 PDF 文件。

C# 中模式匹配的優點

C# 程式碼中的模式匹配具有許多優點:

-增強可讀性:模式匹配簡化了複雜的條件邏輯,使您的程式碼更容易被自己和其他開發人員理解和遵循。 -減少程式碼行數:透過將複雜的條件語句簡化為簡潔的模式,模式匹配有助於簡化程式碼庫,從而減少程式碼行數並實現更簡潔的實作。 -提高可維護性:模式匹配帶來的清晰性有助於更輕鬆地進行程式碼維護和偵錯。 有了清楚劃分的模式,識別和修改特定邏輯區塊就變得更簡單,而不會影響程式碼的其他部分。 -更具表現力的演算法:模式匹配使開發人員能夠以更自然、更直觀的方式表達演算法。 透過將代碼結構與問題解決範例相結合,模式匹配有助於建立與概念模型非常相似的演算法。

C# 中模式匹配的類型

下列表達式支援模式匹配:

  • is 表達式
  • switch 語句
  • switch 表達式

可使用下列模式與構成搭配:

宣告與類型模式

在 C# 中,聲明和類型模式是檢查表達式執行時間類型與給定類型相容性的基本工具。使用宣告模式,您可以同時檢查相容性和宣告新的局部變數。 請考慮以下範例:

object greeting = "Iron Software is Awesome!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  // output: iron software is awesome!
}
object greeting = "Iron Software is Awesome!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  // output: iron software is awesome!
}
Dim greeting As Object = "Iron Software is Awesome!"
Dim tempVar As Boolean = TypeOf greeting Is String
Dim message As String = If(tempVar, DirectCast(greeting, String), Nothing)
If tempVar Then
	Console.WriteLine(message.ToLower()) ' output: iron software is awesome!
End If
$vbLabelText   $csharpLabel

在這裡,聲明模式確保如果表達式 greeting 與類型 string 匹配,則將其賦值給變數 message,從而啟用後續操作。

當下列任何條件成立時,聲明模式成立:

  • 此表達式的運行時類型為 T
  • 表達式的運行時類型派生自 T,實現了 T 接口,或者可以隱式轉換為 T
  • 此表達式的運行時類型是可為空的值類型,其底層類型為 T
  • 存在從表達式的運行時類型到類型 T 的裝箱或拆箱轉換。

請考慮以下示範上述條件的範例:

int? nullableX = 8;
int y = 45;
object boxedy = y;
if (nullableX is int a && boxedy is int b)
{
    Console.WriteLine(a + b);  // output: 53
}
int? nullableX = 8;
int y = 45;
object boxedy = y;
if (nullableX is int a && boxedy is int b)
{
    Console.WriteLine(a + b);  // output: 53
}
Dim nullableX? As Integer = 8
Dim y As Integer = 45
Dim boxedy As Object = y
Dim tempVar As Boolean = TypeOf boxedy Is Integer
Dim b As Integer = If(tempVar, DirectCast(boxedy, Integer), Nothing)
Dim tempVar2 As Boolean = TypeOf nullableX Is Integer
Dim a As Integer = If(tempVar2, CInt(nullableX), Nothing)
If tempVar2 AndAlso tempVar Then
	Console.WriteLine(a + b) ' output: 53
End If
$vbLabelText   $csharpLabel

這裡,nullableX 符合模式,因為它是一個可為空的值類型,其底層類型為 int,而 boxedy 符合模式,因為它可以拆箱為 @@--CODE-22314--@@。

當您只需要檢查表達式的類型而無需宣告新變數時,可以使用 discard _,如下例所示:

public static decimal CalculateToll(Vehicle vehicle) => vehicle switch
{
    Bus _ => 4.00m,
    Motor _ => 8.50m,
    null => throw new ArgumentNullException(nameof(vehicle)),
    _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
public static decimal CalculateToll(Vehicle vehicle) => vehicle switch
{
    Bus _ => 4.00m,
    Motor _ => 8.50m,
    null => throw new ArgumentNullException(nameof(vehicle)),
    _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'public static decimal CalculateToll(Vehicle vehicle) => vehicle switch
'{
'	Bus _ => 4.00m,
'	Motor _ => 8.50m,
'	null => throw new ArgumentNullException(nameof(vehicle)),
'	_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
'};
$vbLabelText   $csharpLabel

在此程式碼片段中,_ 用作與 Vehicle 相符的任何類型的佔位符。

聲明和類型模式都會在模式匹配前確保表達式是非空的。 您可以使用否定 null 常數模式檢查是否為非空,如下圖所示:

if (inputVal is not null)
{
    // ...
}
if (inputVal is not null)
{
    // ...
}
If inputVal IsNot Nothing Then
	' ...
End If
$vbLabelText   $csharpLabel

此否定操作確保在進行進一步操作之前,inputVal 不為空。

透過利用 C# 程式碼中的宣告和類型模式,您可以增強可讀性、減少程式碼行數,並更有效地表達演算法。 這些模式提供簡潔且具表達力的方式來處理基於類型的邏輯,並改善程式碼庫的可維護性。

常規模式

常數模式用來驗證表達式的結果是否符合特定的常數值。 請考慮以下範例:

public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
    1 => 2.0m,
    2 => 10.0m,
    3 => 25.0m,
    4 => 60.0m,
    0 => 0.0m,
    _ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
    1 => 2.0m,
    2 => 10.0m,
    3 => 25.0m,
    4 => 60.0m,
    0 => 0.0m,
    _ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
Dim tempVar As Decimal
Select Case visitorCount
	Case 1
		tempVar = 2.0D
	Case 2
		tempVar = 10.0D
	Case 3
		tempVar = 25.0D
	Case 4
		tempVar = 60.0D
	Case 0
		tempVar = 0.0D
	Case Else
'INSTANT VB TODO TASK: Throw expressions are not converted by Instant VB:
'ORIGINAL LINE: tempVar = throw new ArgumentException(string.Format("Not supported number of visitors: {0}", visitorCount), nameof(visitorCount));
		tempVar = throw New ArgumentException($"Not supported number of visitors: {visitorCount}", NameOf(visitorCount))
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'public static decimal GetGroupTicketPrice(int visitorCount)
'{
'	Return tempVar;
'}
$vbLabelText   $csharpLabel

在這裡,常數模式檢查 visitorCount 是否與任何指定的常數值匹配,並返回相應的票價。

在常數模式中,您可以運用各種類型的常數表達式,例如:

1.整數或浮點數字字面意義。 2.字元。 3.字串字面意義。

  1. 布林值(truefalse)。 5.枚舉值。 6.已宣告的 const 欄位或 local 的名稱。
  2. null

類型為 Span<char>ReadOnlySpan<char> 的表達式可以符合常數字串。

若要檢查 null,請使用如下所示的常數模式:

if (inputVal is null)
{
    return;
}
if (inputVal is null)
{
    return;
}
If inputVal Is Nothing Then
	Return
End If
$vbLabelText   $csharpLabel

此處的模式確保在進行進一步操作之前,inputVal 為空。

您也可以使用否定 null 常數模式來確定非空值:

if (inputVal is not null)
{
    // ...
}
if (inputVal is not null)
{
    // ...
}
If inputVal IsNot Nothing Then
	' ...
End If
$vbLabelText   $csharpLabel

此模式驗證 inputVal 不為空,從而可以安全地執行後續操作。

透過在 C# 程式碼中加入常數模式,您可以有效處理需要匹配特定常數值的情況,改善程式碼的清晰度與可維護性。

關聯模式

關聯模式提供了將表達結果與常量進行比較的方法。 請考慮以下範例:

Console.WriteLine(Classify(20));  // output: Too high
Console.WriteLine(Classify(double.NaN));  // output: Unknown
Console.WriteLine(Classify(4));  // output: Acceptable

static string Classify(double measurement) => measurement switch
{
    < -4.0 => "Too low",
    > 10.0 => "Too high",
    double.NaN => "Unknown",
    _ => "Acceptable",
};
Console.WriteLine(Classify(20));  // output: Too high
Console.WriteLine(Classify(double.NaN));  // output: Unknown
Console.WriteLine(Classify(4));  // output: Acceptable

static string Classify(double measurement) => measurement switch
{
    < -4.0 => "Too low",
    > 10.0 => "Too high",
    double.NaN => "Unknown",
    _ => "Acceptable",
};
Console.WriteLine(Classify(20)) ' output: Too high
Console.WriteLine(Classify(Double.NaN)) ' output: Unknown
Console.WriteLine(Classify(4)) ' output: Acceptable

'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'static string Classify(double measurement) => measurement switch
'{
'	< -4.0 => "Too low",
'	> 10.0 => "Too high",
'	double.NaN => "Unknown",
'	_ => "Acceptable",
'};
$vbLabelText   $csharpLabel

在這裡,關係模式將 measurement 與特定閾值進行比較,以確定其分類。

關係模式的右側部分必須是常數表達式,可以是整數、浮點數、charenum 型。 <><=>= 運算子可在左側使用。

若要在特定範圍內匹配表達結果,請使用結合"和"模式,如下圖所示:

Console.WriteLine(GetCalendarSeason(new DateTime(2024, 3, 12)));  // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 7, 12)));  // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 2, 12)));  // 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}."),
};
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 3, 12)));  // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 7, 12)));  // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 2, 12)));  // 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}."),
};
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 3, 12))) ' output: spring
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 7, 12))) ' output: summer
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 2, 12))) ' output: winter

'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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}."),
'};
$vbLabelText   $csharpLabel

本節錄描述如何利用結合 "and "模式,根據特定範圍內的月份來確定曆季。 其中還提到關聯模式提供了一種簡潔且具表達力的方式,可將表達結果與常量進行比較,從而提高程式碼的清晰度和可維護性。

捨棄模式

丟棄模式,以 _ 表示,用於匹配任何表達式,包括 null。 以下面的例子為例:

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,
};
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,
};
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)) ' output: 5.0
Console.WriteLine(GetDiscountInPercent(Nothing)) ' output: 0.0
Console.WriteLine(GetDiscountInPercent(CType(10, DayOfWeek))) ' output: 0.0

Dim tempVar As Decimal
Select Case dayOfWeek
	Case DayOfWeek.Monday
		tempVar = 0.5D
	Case DayOfWeek.Tuesday
		tempVar = 12.5D
	Case DayOfWeek.Wednesday
		tempVar = 7.5D
	Case DayOfWeek.Thursday
		tempVar = 12.5D
	Case DayOfWeek.Friday
		tempVar = 5.0D
	Case DayOfWeek.Saturday
		tempVar = 2.5D
	Case DayOfWeek.Sunday
		tempVar = 2.0D
	Case Else
		tempVar = 0.0D
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'static decimal GetDiscountInPercent(System.Nullable(Of DayOfWeek) dayOfWeek)
'{
'	Return tempVar;
'}
$vbLabelText   $csharpLabel

在上面的丟棄模式範例中,它處理所有可能的輸入值。 所有的星期都會被管理,並提供預設值。 藉此處理所有可能的數值。 丟棄模式不能用作 is 表達式或 switch 語句中的模式。 在這種情況下,可以使用 var 模式和丟棄項,例如 var _,來匹配任何表達式。 但是,在 switch 表達式中允許使用丟棄模式。 如需更多詳細資訊,請參閱功能提案說明中的捨棄模式部分。

邏輯模式

C# 中的邏輯模式提供了強大的模式匹配工具,包括否定、連結和析取,讓匹配條件更具彈性和表達力。

否定(not 模式)

否定模式(以 not 表示)與表達式匹配,當否定模式與表達式不匹配時,此否定模式匹配該表達式。 這對於檢查表達式是否為非空特別有用,如下所示:

if (input is not null)
{
    // ...
}
if (input is not null)
{
    // ...
}
If input IsNot Nothing Then
	' ...
End If
$vbLabelText   $csharpLabel

如果 input 不為空,則執行此程式碼區塊。

連接詞(and 模式)

使用 and 關鍵字的合取模式,當兩個模式都與表達式相符時,表達式才會相符。 這樣就可以結合多種條件,如下例所示:

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",
};
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",
};
Console.WriteLine(Classify(13)) ' output: High
Console.WriteLine(Classify(-100)) ' output: Too low
Console.WriteLine(Classify(5.7)) ' output: Acceptable

'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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",
'};
$vbLabelText   $csharpLabel

在這個例子中,measurement 根據其值範圍進行分類。

析取 (or 模式)

使用 or 關鍵字的析取模式,當任一模式與表達式相符時,表達式就會相符。 這樣可以處理多種可能的狀況,如下所示:

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}."),
};
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}."),
};
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

Dim tempVar As String
Select Case [date].Month
	Case 3, 4, 5
		tempVar = "spring"
	Case 6, 7, 8
		tempVar = "summer"
	Case 9, 10, 11
		tempVar = "autumn"
	Case 12, 1, 2
		tempVar = "winter"
	Case Else
'INSTANT VB TODO TASK: Throw expressions are not converted by Instant VB:
'ORIGINAL LINE: tempVar = throw new ArgumentOutOfRangeException(nameof(date), string.Format("Date with unexpected month: {0}.", date.Month));
		tempVar = throw New ArgumentOutOfRangeException(NameOf([date]), $"Date with unexpected month: {[date].Month}.")
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'static string GetCalendarSeason(DateTime @date)
'{
'	Return tempVar;
'}
$vbLabelText   $csharpLabel

在此,曆季是根據所提供日期的月份來決定的。

這些模式組合器可重複使用,以建立更複雜、更精準的匹配條件,增強程式碼的靈活性和可讀性。

屬性模式

屬性模式可將表達式的屬性或欄位與巢狀模式進行比對。 下面的程式碼片段就是一個例子:

static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
Shared Function IsConferenceDay(ByVal [date] As DateTime) As Boolean
'INSTANT VB TODO TASK: The following 'is' operator pattern is not converted by Instant VB:
	Return [date] is { Year: 2020, Month: 5, Day: 19 [or] 20 [or] 21 }
End Function
$vbLabelText   $csharpLabel

在此,屬性模式可確保所提供的日期與指定的會議日之一相符。

您也可以在屬性模式中加入執行時類型檢查和變數宣告,如下所示:

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("Unsupported input type."),
};
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("Unsupported input type."),
};
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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("Unsupported input type."),
'};
$vbLabelText   $csharpLabel

在此,使用屬性模式來處理字串和字元集合,以確保根據其屬性進行適當的處理。

定位模式

在 C# 中,位置模式允許解構表達式結果,並將結果值與對應的嵌套模式進行匹配。 舉例來說

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",
};
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",
};
'INSTANT VB WARNING: VB has no equivalent to the C# readonly struct:
'ORIGINAL LINE: public readonly struct Point
Public Structure Point
	Public ReadOnly Property X() As Integer
	Public ReadOnly Property Y() As Integer
	Public Sub New(ByVal x As Integer, ByVal y As Integer)
'INSTANT VB TODO TASK: VB has no equivalent to the C# deconstruction assignments:
		(X, Y) = (x, y)
	End Sub
	Public Sub Deconstruct(<System.Runtime.InteropServices.Out()> ByRef x As Integer, <System.Runtime.InteropServices.Out()> ByRef y As Integer)
'INSTANT VB TODO TASK: VB has no equivalent to the C# deconstruction assignments:
		(x, y) = (X, Y)
	End Sub
End Structure

'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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",
'};
$vbLabelText   $csharpLabel

在這個範例中,我們利用位置模式來根據坐標將點分類。

此外,您可以在 C# 10 中引入的屬性模式(稱為擴展屬性模式)中引用巢狀屬性或欄位:

static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start.Y: 0 } or { End.Y: 0 };
static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start.Y: 0 } or { End.Y: 0 };
Shared Function IsAnyEndOnXAxis(ByVal segment As Segment) As Boolean
'INSTANT VB TODO TASK: The following 'is' operator pattern is not converted by Instant VB:
	Return segment is { Start.Y: 0 } [or] { [End].Y: 0 }
End Function
$vbLabelText   $csharpLabel

此功能允許直接存取巢狀的屬性,增強了屬性模式的靈活性。

這些模式提供了強大的機制來處理複雜的資料結構,並改善程式碼的可讀性和表達力。

Var 模式

Var Pattern 可讓您匹配任何類型。 這對於擷取布林表達式中的中間結果,或在 switch case 保護中需要多重檢查時,尤其有用。

以下是一個示範在布林表達式中使用 var 模式的範例:

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();
}
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();
}
Shared Function IsAcceptable(ByVal id As Integer, ByVal absLimit As Integer) As Boolean
	Dim tempVar As Boolean = TypeOf SimulateDataFetch(id) Is var
	Dim results = If(tempVar, CType(SimulateDataFetch(id), var), Nothing)
	Return tempVar AndAlso results.Min() >= -absLimit AndAlso results.Max() <= absLimit
End Function

Shared Function SimulateDataFetch(ByVal id As Integer) As Integer()
	Dim rand = New Random()
	Return Enumerable.Range(start:= 0, count:= 5).Select(Function(s) rand.Next(minValue:= -10, maxValue:= 11)).ToArray()
End Function
$vbLabelText   $csharpLabel

在這個例子中,SimulateDataFetch 傳回一個整數數組,而 is var 模式將結果捕獲到 results 變數中,從而可以根據其屬性進行後續計算。

此外,可以在 switch 表達式或語句中使用 var 模式,以獲得更簡潔、更易讀的程式碼。 以下是一個在 switch case 保護中使用 var 模式的範例:

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 }
}
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 }
}
'INSTANT VB TODO TASK: C# 'records' are not converted by Instant VB:
'public record Point(int X, int Y)

'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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),
'};

Shared Sub 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 }
End Sub
$vbLabelText   $csharpLabel

在這個例子中,變數模式 (x, y) 捕獲點的座標,允許根據其值進行不同的變換。

在 var 模式中,所宣告變數的類型會從與模式匹配的表達式的編譯時類型中推斷出來。

var 模式提供了一種方便的方式來處理事先不知道具體表達類型的各種情況,提高了程式碼的清晰度和靈活性。

介紹 IronPDF Library

IronPDF文件渲染是Iron Software推出的一個專門用於PDF文件生成的庫。 要開始使用,首先要從 NuGet 套件管理員或 Visual Studio 套件管理員安裝函式庫。

# To install from the NuGet Package Manager Console
Install-Package IronPdf
# To install from the NuGet Package Manager Console
Install-Package IronPdf
SHELL

下圖顯示如何從 Visual Studio 安裝指南進行安裝。

C# Pattern Matching Expressions (How It Works For Developers):圖 1 - 使用 NuGet 套件管理員安裝 IronPDF

在下面的程式碼中,我們將看到如何產生一個簡單的 PDF 文件:

using IronPdf;

namespace IronPatterns
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine("-----------Iron Software-------------");
            var renderer = new ChromePdfRenderer(); // var pattern
            var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";

            // Declaration Pattern
            int? nullableX = 8;
            int y = 45;
            object boxedy = y;
            content += "<p>Declaration Pattern</p>";
            if (nullableX is int a && boxedy is int b)
            {
                Console.WriteLine(a + b); // output: 53
                content += $"<p>Output: {(a + b)}</p>";
            }

            // Relational patterns
            content += "<p>Relational patterns</p>";
            var season1 = GetCalendarSeason(new DateTime(2024, 2, 25));
            Console.WriteLine(season1);
            content += $"<p>2024, 2, 25: {season1}</p>";
            var season2 = GetCalendarSeason(new DateTime(2024, 5, 25));
            Console.WriteLine(season2);
            content += $"<p>2024, 5, 25: {season2}</p>";
            var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
            Console.WriteLine(season3);
            content += $"<p>2024, 7, 25: {season3}</p>";

            var pdf = renderer.RenderHtmlAsPdf(content);
            pdf.SaveAs("output.pdf"); // Saves our PdfDocument object as a PDF        
        }

        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}."),
        };
    }
}
using IronPdf;

namespace IronPatterns
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine("-----------Iron Software-------------");
            var renderer = new ChromePdfRenderer(); // var pattern
            var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";

            // Declaration Pattern
            int? nullableX = 8;
            int y = 45;
            object boxedy = y;
            content += "<p>Declaration Pattern</p>";
            if (nullableX is int a && boxedy is int b)
            {
                Console.WriteLine(a + b); // output: 53
                content += $"<p>Output: {(a + b)}</p>";
            }

            // Relational patterns
            content += "<p>Relational patterns</p>";
            var season1 = GetCalendarSeason(new DateTime(2024, 2, 25));
            Console.WriteLine(season1);
            content += $"<p>2024, 2, 25: {season1}</p>";
            var season2 = GetCalendarSeason(new DateTime(2024, 5, 25));
            Console.WriteLine(season2);
            content += $"<p>2024, 5, 25: {season2}</p>";
            var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
            Console.WriteLine(season3);
            content += $"<p>2024, 7, 25: {season3}</p>";

            var pdf = renderer.RenderHtmlAsPdf(content);
            pdf.SaveAs("output.pdf"); // Saves our PdfDocument object as a PDF        
        }

        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}."),
        };
    }
}
Imports IronPdf

Namespace IronPatterns
	Friend Class Program
		Shared Sub Main()
			Console.WriteLine("-----------Iron Software-------------")
			Dim renderer = New ChromePdfRenderer() ' var pattern
			Dim content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!"

			' Declaration Pattern
			Dim nullableX? As Integer = 8
			Dim y As Integer = 45
			Dim boxedy As Object = y
			content &= "<p>Declaration Pattern</p>"
			Dim tempVar As Boolean = TypeOf boxedy Is Integer
			Dim b As Integer = If(tempVar, DirectCast(boxedy, Integer), Nothing)
			Dim tempVar2 As Boolean = TypeOf nullableX Is Integer
			Dim a As Integer = If(tempVar2, CInt(nullableX), Nothing)
			If tempVar2 AndAlso tempVar Then
				Console.WriteLine(a + b) ' output: 53
				content &= $"<p>Output: {(a + b)}</p>"
			End If

			' Relational patterns
			content &= "<p>Relational patterns</p>"
			Dim season1 = GetCalendarSeason(New DateTime(2024, 2, 25))
			Console.WriteLine(season1)
			content &= $"<p>2024, 2, 25: {season1}</p>"
			Dim season2 = GetCalendarSeason(New DateTime(2024, 5, 25))
			Console.WriteLine(season2)
			content &= $"<p>2024, 5, 25: {season2}</p>"
			Dim season3 = GetCalendarSeason(New DateTime(2024, 7, 25))
			Console.WriteLine(season3)
			content &= $"<p>2024, 7, 25: {season3}</p>"

			Dim pdf = renderer.RenderHtmlAsPdf(content)
			pdf.SaveAs("output.pdf") ' Saves our PdfDocument object as a PDF
		End Sub

'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'		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}."),
'		};
	End Class
End Namespace
$vbLabelText   $csharpLabel

輸出

C# Pattern Matching Expressions (How It Works For Developers):圖 2

程式碼詳細資料

這裡我們使用IronPDF 的 ChromePdfRenderer 類別將 HTML 字串儲存到 PDF 文件中。 輸出結果會儲存在"output.pdf"文件中。

試用授權

IronPDF 可以使用從 IronPDF 授權頁面取得的 試用授權。 提供電子郵件 ID 以產生授權金鑰,並傳送到您的電子郵件。

"IronPdf.LicenseKey": "<Your Key>"
"IronPdf.LicenseKey": "<Your Key>"
"IronPdf.LicenseKey" = "<Your Key>"
$vbLabelText   $csharpLabel

將許可證金鑰放入如上所示的 appsettings.json 檔案中。

結論

C# 中的模式匹配表達式提供了一種強大而靈活的方式,以簡潔可讀的方式撰寫條件語句、類型檢查和物件解構。 透過利用模式匹配,開發人員可以提高程式碼的清晰度和可維護性,同時減少模板和冗餘。 無論是類型檢查、切換語句或解構,模式匹配表達式都提供了一個多功能的工具集,可用於處理 C# 中的各種程式設計任務。

總而言之,掌握模式匹配表達式可大幅提升 C# 程式設計技巧,讓您能寫出更乾淨、更具表達力的程式碼,而且更容易理解與維護。 我們還介紹了 IronPDF的HTML轉PDF生成能力,可以利用它來生成PDF文件。

常見問題解答

我如何使用模式匹配來提高 C# 中代碼的可讀性?

C# 中的模式匹配允許開發人員編寫更簡潔和富於表達的代碼,使條件語句更清晰且易於理解。這通過減少代碼塊的複雜性來提高了可讀性和可維護性。

C# 中提供哪些不同類型的模式匹配表達式?

C# 支持多種模式匹配表達式,包括 is 表達式,switch 語句和 switch 表達式。每種類型都提供了不同的方式來評估表達式並根據匹配模式執行代碼。

我如何使用 C# 生成 PDF 文檔?

您可以使用 IronPDF,這是來自 Iron Software 的庫,用於在 C# 中生成 PDF 文檔。它允許將 HTML 內容轉換成 PDF,並可通過 NuGet 輕鬆安裝,提供了豐富的 PDF 生成功能。

什麼是 C# 模式匹配中的聲明和類型模式?

C# 中的聲明和類型模式檢查一個表達式的運行時類型是否與一個指定的類型匹配,並允許在匹配成功時聲明一個新的局部變量,以促進類型安全的操作。

C# 中的常量模式如何運行?

C# 中的常量模式用於檢查一個表達式是否等於一個特定的常量值,如整數或字符串,並在找到匹配時執行某些邏輯,從而實現簡單的常量值比較。

C# 中的關係模式的用途是什麼?

C# 中的關係模式允許使用關係運算符如 <><=>= 將表達式與常量進行比較。這對於在代碼中實現簡潔的範圍檢查很有用。

如何在 C# 中應用邏輯模式?

C# 中的邏輯模式使用邏輯運算符如 andornot 組合其他模式,允許為復雜的模式匹配條件設置,可同時評估多個標準。

C# 中的丟棄模式是什麼,何時使用?

C# 中的丟棄模式,由 _ 表示,匹配任何表達式,包括 null,通常用於需要忽略特定值的情況,例如在 switch 表達式中使用。

如何在 C# 中利用屬性模式?

C# 中的屬性模式允許開發人員將一個對象的屬性或字段與嵌套模式進行匹配,提供了一種在維持清晰簡潔代碼的同時進行對象結構深層檢查的方法。

Jacob Mellor, Team Iron 首席技術官
首席技術官

Jacob Mellor是Iron Software的首席技術官,也是開創C# PDF技術的前瞻性工程師。作為Iron Software核心代碼庫的原始開發者,他自公司成立以來就塑造了公司的產品架構,並與CEO Cameron Rimington將公司轉型為服務NASA、Tesla以及全球政府機構的50多人公司。

Jacob擁有曼徹斯特大學土木工程一級榮譽學士學位(1998年–2001年)。他於1999年在倫敦開立首家軟體公司,並於2005年建立了他的第一個.NET組件,專注於解決Microsoft生態系統中的複雜問題。

他的旗艦作品IronPDF和Iron Suite .NET程式庫全球已獲得超過3000萬次NuGet安裝,他的基礎代碼不斷在全球各地驅動開發者工具。擁有25年以上的商業經驗和41年的編碼專業知識,Jacob仍然專注於推動企業級C#、Java和Python PDF技術的創新,同時指導下一代技術領導者。

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我