# 模式比對Pattern Matching

public class Square
{
public double Side { get; }

public Square(double side)
{
Side = side;
}
}
public class Circle
{
public double Radius { get; }

{
}
}
public struct Rectangle
{
public double Length { get; }
public double Height { get; }

public Rectangle(double length, double height)
{
Length = length;
Height = height;
}
}
public class Triangle
{
public double Base { get; }
public double Height { get; }

public Triangle(double @base, double height)
{
Base = @base;
Height = height;
}
}


## is 型別模式運算式The is type pattern expression

public static double ComputeArea(object shape)
{
if (shape is Square)
{
var s = (Square)shape;
return s.Side * s.Side;
}
else if (shape is Circle)
{
var c = (Circle)shape;
}
// elided
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}


public static double ComputeAreaModernIs(object shape)
{
if (shape is Square s)
return s.Side * s.Side;
else if (shape is Circle c)
else if (shape is Rectangle r)
return r.Height * r.Length;
// elided
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}


## 使用模式比對 switch 陳述式Using pattern matching switch statements

public static string GenerateMessage(params string[] parts)
{
switch (parts.Length)
{
case 0:
return "No elements to the input";
case 1:
return $"One element: {parts[0]}"; case 2: return$"Two elements: {parts[0]}, {parts[1]}";
default:
return \$"Many elements. Too many to write";
}
}


switch 陳述式以前支援的唯一模式是常數模式。The only pattern supported by the switch statement was the constant pattern. 以前更限制為數值型別和 string 型別。It was further limited to numeric types and the string type. 這些限制現已移除，而且您可以使用型別模式撰寫 switch 陳述式︰Those restrictions have been removed, and you can now write a switch statement using the type pattern:

public static double ComputeAreaModernSwitch(object shape)
{
switch (shape)
{
case Square s:
return s.Side * s.Side;
case Circle c:
case Rectangle r:
return r.Height * r.Length;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}


## case 運算式中的 when 子句when clauses in case expressions

case 標籤使用 when 子句，可為面積為 0 的圖形建立特殊案例。You can make special cases for those shapes that have 0 area by using a when clause on the case label. 邊長為 0 的正方形或半徑為 0 的圓形，面積皆為 0。A square with a side length of 0, or a circle with a radius of 0 has a 0 area. 您可以對 case 標籤使用 when 子句來指定該條件︰You specify that condition using a when clause on the case label:

public static double ComputeArea_Version3(object shape)
{
switch (shape)
{
case Square s when s.Side == 0:
case Circle c when c.Radius == 0:
return 0;

case Square s:
return s.Side * s.Side;
case Circle c:
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}


public static double ComputeArea_Version4(object shape)
{
switch (shape)
{
case Square s when s.Side == 0:
case Circle c when c.Radius == 0:
case Triangle t when t.Base == 0 || t.Height == 0:
case Rectangle r when r.Length == 0 || r.Height == 0:
return 0;

case Square s:
return s.Side * s.Side;
case Circle c:
case Triangle t:
return t.Base * t.Height / 2;
case Rectangle r:
return r.Length * r.Height;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}


public static double ComputeArea_Version5(object shape)
{
switch (shape)
{
case Square s when s.Side == 0:
case Circle c when c.Radius == 0:
case Triangle t when t.Base == 0 || t.Height == 0:
case Rectangle r when r.Length == 0 || r.Height == 0:
return 0;

case Square s:
return s.Side * s.Side;
case Circle c:
case Triangle t:
return t.Base * t.Height / 2;
case Rectangle r:
return r.Length * r.Height;
case null:
throw new ArgumentNullException(paramName: nameof(shape), message: "Shape must not be null");
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}


## case 運算式中的 var 宣告var declarations in case expressions

static object CreateShape(string shapeDescription)
{
switch (shapeDescription)
{
case "circle":
return new Circle(2);

case "square":
return new Square(4);

case "large-circle":
return new Circle(12);

case var o when (o?.Trim().Length ?? 0) == 0:
// white space
return null;
default:
return "invalid shape description";
}
}


var 案例符合 null、空字串或任何僅包含空格的字串。The var case matches null, the empty string, or any string that contains only white space. 留意到上述程式碼會使用 ?. 運算子來確保它不會意外地擲回 NullReferenceExceptionNotice that the preceding code uses the ?. operator to ensure that it doesn't accidentally throw a NullReferenceException. default 狀況會處理此命令剖析器無法理解的任何其他字串值。The default case handles any other string values that aren't understood by this command parser.

## 結論Conclusions

「模式比對建構」** 可讓您輕鬆管理不依繼承階層關聯之不同變數和類型的控制流程。Pattern Matching constructs enable you to easily manage control flow among different variables and types that aren't related by an inheritance hierarchy. 您也可以控制邏輯，在變數上使用任何測試條件。You can also control logic to use any condition you test on the variable. 在您建置分散程度更高的應用程式時，即資料和操作資料的方法是分開的，它可讓您使用最常用的模式和慣用句。It enables patterns and idioms that you'll need more often as you build more distributed applications, where data and the methods that manipulate that data are separate. 您會發現此範例所使用的圖形結構不包含任何方法，只有唯讀屬性。You'll notice that the shape structs used in this sample don't contain any methods, just read-only properties. 模式比對適用於任何資料型別。Pattern Matching works with any data type. 您會撰寫檢查物件的運算式，並根據這些條件決定控制流程。You write expressions that examine the object, and make control flow decisions based on those conditions.