跳至页脚内容
.NET 帮助

C# 模式匹配表达式(开发人员如何使用)

C#中的模式匹配是一个强大的功能,引入于C# 7.0,并在后续版本中不断扩展。 它允许开发人员在处理条件语句、类型检查和对象解构时编写更简洁和表达力更强的代码。

模式匹配表达式提供了一种灵活且直观的方式,用于将值与模式进行匹配并执行相应的代码块。 在本文中,我们将深入探讨C#中模式匹配表达式的细节,包括语法、用例和代码示例。 At the end of the article, we will also explore a bit about IronPDF PDF Generation Library from Iron Software to generate a PDF document on the fly in C# applications.

C#中模式匹配的好处

C#代码中的模式匹配带来诸多优势:

  • 提升可读性:模式匹配简化了复杂的条件逻辑,使您的代码更易于理解和遵循,不仅对于您自己,也对其他开发人员。
  • 减少代码行数:通过将复杂的条件语句压缩为简洁的模式,模式匹配有助于简化代码库,从而减少代码行数,实现更简洁的实现。
  • 提高可维护性:模式匹配带来的清晰性有利于更轻松的代码维护和调试。 由于明确划分了模式,便于在需要时识别和修改特定的逻辑块,而不影响其余代码库。
  • 更具表达力的算法:模式匹配使开发人员能够以更自然和直观的方式表达算法。 通过将代码结构与问题解决范式对齐,模式匹配促进创建与其概念模型更为相似的算法。

C#中模式匹配的类型

以下表达式支持模式匹配:

  • is表达式
  • switch语句
  • switch表达式

可以使用以下模式来与构造匹配:

声明和类型模式

声明和类型模式是在C#中检查表达式运行时类型与给定类型兼容的基本工具。利用声明模式,您可以同时检查兼容性并声明新的局部变量。 在此示例中,IronPDF用于将HTML内容渲染为PDF文档,然后保存到指定位置。

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匹配,因为可以将其拆箱为int

当只需检查表达式的类型而不声明新变量时,可以使用丢弃_,如下面的示例所示:

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#代码中利用声明和类型模式,可以提高可读性,减少代码行数,更有效地表达算法。 这些模式提供了一种简洁和具有表现力的方式来处理基于类型的逻辑,提高您的代码库的可维护性。

常量模式

常量模式用于验证表达式结果是否匹配特定常量值。 在此示例中,IronPDF用于将HTML内容渲染为PDF文档,然后保存到指定位置。

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. 字符串字面量。
  4. 布尔值(truefalse)。
  5. 枚举值。
  6. 声明的const字段或局部变量的名称。
  7. 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#代码中,可以有效处理需要匹配特定常量值的场景,提高代码的清晰性和可维护性。

关系模式

关系模式提供了一种手段,将表达式结果与常量进行比较。 在此示例中,IronPDF用于将HTML内容渲染为PDF文档,然后保存到指定位置。

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

这段摘录描述了如何利用合取“和”模式,根据月份落在特定范围内来确定日历季节。 还提到关系模式提供了一种简洁而表达力强的方式来将表达式结果与常量进行比较,从而增强代码的清晰性和可维护性。

丢弃模式

丢弃模式,以_表示,旨在匹配任何表达式,包括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不为null时执行。

合取(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#中,位置模式允许解构表达式结果,并将获得的值与相应的嵌套模式进行匹配。 PDF创建和PDF生成被iText 7支持,而HTML到PDF的转换则由pdfHTML支持。

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模式允许您匹配任何类型。 这在布尔表达式中捕获中间结果或需要在switch案例守护中进行多次检查时尤其有用。

以下是使用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变量中,允许根据其属性进行后续计算。

此外,var模式可以在switch表达式或语句中使用,使代码更加简洁和易读。 以下是在switch案例守护中使用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

在此示例中,var模式(x, y)捕获点的坐标,根据其值进行不同的变换。

在var模式中,声明变量的类型从与模式匹配的表达式的编译时类型推断。

Var模式提供了一种方便的方式来处理在事先不知道表达式的具体类型的各种场景,提高代码的清晰性和灵活性。

介绍IronPDF库

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#模式匹配表达式(对开发者的运作方式):图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#模式匹配表达式(对开发者的运作方式):图2

代码详情

这里我们使用IronPDF的ChromePdfRenderer将HTML字符串保存到PDF文档中。 输出保存到"output.pdf"文档中。

试用许可

IronPDF can be used with a trial license obtained from the IronPDF Licensing Page. 提供一个电子邮件地址以生成许可证密钥,该密钥将发送到您的电子邮件中。

"IronPDF.LicenseKey": "<Your Key>"
"IronPDF.LicenseKey": "<Your Key>"
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'"IronPDF.LicenseKey": "<Your Key>"
$vbLabelText   $csharpLabel

将许可证密钥放入appsettings.json文件中,如上所示。

结论

C#中的模式匹配表达式提供了一种强大而灵活的方式,以简洁和易读的方式编写条件语句、类型检查和对象解构。 通过利用模式匹配,开发人员可以提升代码的清晰度和可维护性,同时减少样板代码和冗余。 无论是类型检查、switch语句,还是解构,模式匹配表达式为在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# 中的属性模式允许开发人员将对象的属性或字段与嵌套模式进行匹配,提供了一种在维护清晰简洁代码的同时深入检查对象结构的方法。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。