# 模式匹配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

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));
}
}


null 模式的特殊行为十分有趣，因为模式中的常量 null 没有类型，但可以转换为任何引用类型或可以为 null 的值类型。The special behavior for the null pattern is interesting because the constant null in the pattern doesn't have a type but can be converted to any reference type or nullable value type. 语言定义 null 值不会匹配任何类型模式（无论变量的编译时类型如何），而不是将 null 转换为任何类型。Rather than convert a null to any type, the language defines that a null value won't match any type pattern, regardless of the compile-time type of the variable. 此行为使新的基于 switch 的类型模式与 is 语句保持一致：如果检查的值为 nullis 语句始终返回 falseThis behavior makes the new switch based type pattern consistent with the is statement: is statements always return false when the value being checked is null. 它也更简单；也就是说，在检查类型后，便无需执行其他 null 检查。It's also simpler: once you've checked the type, you don't need an additional null check. 可以从上面示例中的任何 case 块都没有 null 检查得知：此类检查不是必需的，因为与类型模式匹配即可保证非 null 值。You can see that from the fact that there are no null checks in any of the case blocks of the samples above: they aren't necessary, since matching the type pattern guarantees a non-null value.

## 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. 请注意，为了确保不会意外抛出 NullReferenceException，上面的代码使用 ?. 运算符。Notice that the preceding code uses the ?. operator to ensure that it doesn't accidentally throw a NullReferenceException. default case 处理此命令分析程序不理解的其他任何字符串值。The default case handles any other string values that aren't understood by this command parser.