在生產環境中測試,無水印。
在任何需要的地方都能運行。
獲得 30 天的全功能產品。
在幾分鐘內上手運行。
試用產品期間完全訪問我們的支援工程團隊
C#中的模式匹配是一個強大功能,首次在C# 7.0中引入,之後在後續版本中進一步擴展。 它允許開發人員在處理條件語句、類型檢查和對物件進行解構時,撰寫更簡潔且富有表現力的代碼。
模式匹配表達式提供了一種靈活且直觀的方法,將值與模式匹配並執行相應的代碼塊。 在本文中,我們將探討 C# 中模式匹配表達式的複雜性,包括語法、使用範例和代碼示例。 在文章的最後,我們還將探索一些有關IronPDF PDF 生成庫從Iron Software在C#應用程式中即時生成PDF文件。
C# 代碼中的模式匹配具有許多優勢:
模式匹配支持以下表達式:
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!
}
這裡,宣告模式確保如果表達式 greeting 匹配類型 string,它會被分配給變數 message,從而啟用後續操作。
當以下任一條件成立時,聲明模式有效:
從運行時的表達式類型到類型 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
}
在這裡,nullableX
符合模式,因為它是一個可空值類型,其基礎類型為 int;boxedy
符合模式,因為它可以解箱為 int。
當你只需要檢查表達式的類型而不聲明新變量時,可以使用丟棄符號 _,如下面範例所示:
public static decimal CalculateToll(this 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(this 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)),
};
在此代码片段中,_ 用作與 Vehicle 類型匹配的任何類型的佔位符。
聲明和類型模式都確保表達式在模式匹配之前非空。 您可以使用否定的空常數模式來檢查非空值,如下所示:
if (inputVal is not null)
{
// ...
}
if (inputVal is not null)
{
// ...
}
此否定確保在進行進一步操作之前,輸入不為空。
透過在您的 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)),
};
在這裡,常數模式檢查 visitorCount
是否與任何指定的常數值匹配,並返回相應的票價。
在常數模式中,您可以使用各種類型的常數表達式,例如:
整數或浮點數字面值。
字符。
字串字面值。
布林值(真或假).
列舉值。
已宣告的常數欄位或區域變數的名稱。
null.
類型為 Span 的表達式
若要檢查是否為 null,使用如下的常數模式:
if (inputVal is null)
{
return;
}
if (inputVal is null)
{
return;
}
在這裡,該模式確保在進行進一步操作之前,輸入為 null。
您也可以使用否定的 null 常量模式來確認非 null 值:
if (inputVal is not null)
{
// ...
}
if (inputVal is not null)
{
// ...
}
此模式驗證輸入不為空,以便後續操作可以安全地執行。
透過將常量模式納入您的 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",
};
在這裡,關係模式將測量值與特定閾值進行比較以確定其分類。
關係模式的右側部分必須是常數表達式,可以是整數、浮點數、字符或 enum
類型。 <
、>
、<=
或 >=
運算子可以用在左側。
要在特定範圍內匹配表達式結果,請使用連接詞和模式,如下所示:
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}."),
};
這段摘錄描述了如何利用連接詞「和」模式來根據月份在特定範圍內確定日曆季節。 它還提到,關聯模式提供了一種簡潔且具表達力的方法來將表達式結果與常量進行比較,從而增強了代碼的清晰度和可維護性。
丟棄模式由 _ 表示,用於匹配任何表達式,包括 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,
};
在上述範例中,丟棄模式處理所有可能的輸入值。 一週中的所有日子都已處理並代表預設值。 這樣所有可能的數值都被處理了。 丟棄模式不能在 is 表達式或 switch 語句中用作模式。 在這種情況下,你可以使用帶有捨棄的var模式,如var _,來匹配任何表達式。 然而,丟棄模式在 switch 表達式中是允許的。 如需進一步詳細信息,請參閱功能提案說明中的放棄模式部分。
C# 中的邏輯模式提供了強大的工具進行模式匹配,包括否定、合取和析取,這使得匹配條件更靈活且更具表達力。
否定模式,由「not」表示,在否定模式不匹配表達式的時候匹配表達式。 這在檢查表達式是否為非空時特別有用,如下所示:
if (input is not null)
{
// ...
}
if (input is not null)
{
// ...
}
這裡,如果輸入不為空,則執行程式碼區塊。
結合模式使用「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",
};
在此範例中,測量根據其數值範圍進行分類。
使用「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}."),
};
在這裡,日曆季節是根據所提供日期的月份來判斷的。
這些模式組合器可以重複使用,以創建更複雜和精確的匹配條件,從而增強代碼的靈活性和可讀性。
屬性模式使得將表達式的屬性或欄位與嵌套模式進行匹配成為可能。 這可以在以下程式碼片段中看到的範例中看到:
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 };
在此,屬性模式確保提供的日期對應於指定的會議日之一。
您還可以在屬性模式中整合運行時類型檢查和變數宣告,如下所示:
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."),
};
在此,屬性模式用於處理字符串和字符集合,確保根據它們的屬性進行適當處理。
在 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",
};
在此範例中,位置模式被用於根據坐標對點進行分類。
此外,您可以引用屬性模式中的嵌套屬性或欄位,這在 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 };
此功能通過允許直接訪問嵌套屬性來增強屬性模式的靈活性。
這些模式提供了強大的機制,用於處理複雜的數據結構,並提高您的代碼的可讀性和表達性。
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();
}
在此示例中,SimulateDataFetch
返回一個整數數組,並使用 is var 模式將結果捕獲到 results 變量中,以便可以基於其屬性進行後續計算。
此外,可以在 switch 表達式或語句中使用變量模式,以編寫更簡潔和更具可讀性的代碼。 以下是一個在 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 }
}
在此範例中,var 模式(x,y)捕捉點的座標,允許根據其值進行不同的轉換。
在 var 模式中,宣告變數的類型是從與模式匹配的表達式編譯時類型推斷而來的。
var 模式提供了一種方便的方法來處理各種情況,在這些情況中,表達式的具體類型事先未知,提高了代碼的清晰度和靈活性。
IronPDF 文件渲染是來自Iron Software的一個專注於PDF文件生成的庫。 要開始,首先從 NuGet 套件管理器或 Visual Studio 套件管理器安裝該庫。
Install-Package IronPdf
下圖顯示了如何從Visual Studio 安裝指南.
在以下程式碼中,我們將看到如何生成一個簡單的 PDF 文件:
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>Ouput:{(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:{season1}</p>";
var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
Console.WriteLine(season3);
content += $"<p>2024, 7, 25:{season1}</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}."),
};
}
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>Ouput:{(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:{season1}</p>";
var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
Console.WriteLine(season3);
content += $"<p>2024, 7, 25:{season1}</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}."),
};
}
在這裡,我們使用IronPDF 的 ChromePdfRenderer
類別將 HTML 字串保存到 PDF 文件中。 輸出儲存為 "output.pdf" 文件。
IronPDF 可以搭配使用試用授權從...獲得的IronPDF 授權頁面. 提供電子郵件地址以生成將發送到您電子郵件的許可證密鑰。
"IronPDF.LicenseKey": "<Your Key>"
"IronPDF.LicenseKey": "<Your Key>"
將授權金鑰放置在 AppSettings.Json 文件中,如上所示。
C# 中的模式匹配表達式提供了一種強大而靈活的方法,可以用簡潔和易讀的方式編寫條件語句、類型檢查和對象解構。 透過利用樣式匹配,開發人員可以提高代碼的清晰度和可維護性,同時減少樣板代碼和冗餘。 無論是類型檢查、switch 語句還是解構,模式匹配表達式都提供了強大的工具組,用於解決 C# 中各種編程任務。
總之,掌握模式匹配表達式可以大大提高您的C#程式設計技能,使您能夠編寫更乾淨、更具表達力的代碼,更易於理解和維護。 我們也涵蓋了IronPDF 的 HTML 到 PDF 生成功能,可以用來生成 PDF 文件。