[译]C#7 Pattern Matching

原文

public struct Square
{
    public double Side { get; }

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

    public Circle(double radius)
    {
        Radius = radius;
    }
}
public struct Rectangle
{
    public double Length { get; }
    public double Height { get; }

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

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

下面,我们写个方法用来计算这些形状的面积。

is 类型模式表达式

在C# 7.0之前,我们需要使用ifis语句去判断类别:

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;
        return c.Radius * c.Radius * Math.PI;
    }
    // elided
    throw new ArgumentException(
        message: "shape is not a recognized shape",
        paramName: nameof(shape));
}

在C# 7.0 中,通过使用is表达式的扩展可以在类型判断成功的时候将其分配给一个变量,从而简化上面的代码:

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

新的is表达式对值类型和引用类型都好使。

上面的例子中,变量scr只有在模式匹配表达式为true的时候才作用被分配。

通过switch语句使用模式匹配

之前switch只支持常量模式。只能讲一个变量和case中的常量进行一个比较:

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

7之前switch只支持常量模式。在C# 7.0 中没有这个限制了,可以通过switch来使用类型模式:

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

case表达式中使用when

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:
            return c.Radius * c.Radius * Math.PI;
        default:
            throw new ArgumentException(
                message: "shape is not a recognized shape",
                paramName: nameof(shape));
    }
}

case表达式中声明变量

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

猜你喜欢

转载自www.cnblogs.com/irocker/p/pattern-matching.html