• C# 7.0 新特性:模式匹配 ( pattern matching)


    C# 7.0 新特性:模式匹配 ( pattern matching )

    在 C# 中,is 是一个关键字,可以用来检查某个数据的类型是否为特定类型。这是一个表达式,返回类型为 boolean。

    例如,我们可以检查某个实例是否为 Persion 类型

    if (obj is Person) {
       // Do something if obj is a Person.
    }

    在下面情况下,返回 true:

    • 表达式的类型与 is 类型相符
    • 表达式的类型为 is 类型的派生类型
    • 表达式具有一个编译时类型, 它是 is 类型的基类,在运行时的值为 is 类型的派生类型
    • 表达式实现了 is 类型的接口

    支持模式匹配的 is

    类型模式

    在 C# 7.0 中,is 在原来的基础上,额外提供了类型转换的支持。可以在类型检查的基础上,直接支持类型转换。

    在下面的示例中,我们希望检查对象的类型,如果为指定类型,我们要转型为特定的类型进行操作。

    using System;
    
    public class Example
    {
       public static void Main()
       {
          Object o = new Person("Jane");
          ShowValue(o);
          
          o = new Dog("Alaskan Malamute");
          ShowValue(o);
       }
    
       public static void ShowValue(object o)
       {
          if (o is Person p) {
             Console.WriteLine(p.Name);
          }   
          else if (o is Dog d) {
             Console.WriteLine(d.Breed);
          }             
       }
    }
    
    public struct Person
    {  
       public string Name { get; set; }
       
       public Person(string name) : this()
       {
          Name = name;
       }
    }
    
    public struct Dog
    {
       public string Breed { get; set; }
    
       public Dog(string breedName) : this()
       {
          Breed = breedName;
       }
    }
    // The example displays the following output:
    //    Jane
    //    Alaskan Malamute

    等价的以前代码为:

    if (o is Person) {
             Person p = (Person) o;
             Console.WriteLine(p.Name);
    }   
    else if (o is Dog) {
             Dog d = (Dog) o;
             Console.WriteLine(d.Breed);
    }

    常量匹配

    is 后面还可以是常量,is 测试表达式的值是否为特定常量。在以前版本中,这需要使用 switch 来支持。

    using System;
    
    public class Dice
    {
        Random rnd = new Random();
        public Dice()
        {
    
        }
        public int Roll()
        {
            return rnd.Next(1, 7); 
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var d1 = new Dice();
            ShowValue(d1);
        }
    
        private static void ShowValue(object o)
        {
            const int HIGH_ROLL = 6;
    
            if (o is Dice d && d.Roll() is HIGH_ROLL)
                Console.WriteLine($"The value is {HIGH_ROLL}!");
            else
                Console.WriteLine($"The dice roll is not a {HIGH_ROLL}!");
         }
    }
    // The example displays output like the following:
    //      The value is 6!

    var 匹配

    如果 is 后面是 var,则永远为 true 。并把值赋予后面的变量。

    例如,下面代码将 item 赋予了 obj。

    if (item is var obj)

    需要注意的是,即使被测试的值为 null,is 表达式还是为 true。此时,变量将被赋予 null。

    支持模式匹配的 Switch

    所有的 c# 版本都支持常量模式,在 C#  7.0 中,现在支持类型模式了。也就是说,在 case 后面还可以是一个用来检测的类型。

    case type varname

    相当于在这里使用了 is 。

    从 C# 7.0 开始,您还可以在上面的表达式后面附加一个返回 boolean 的 when 条件,以进一步检查。使用它的常见场景就是当值为 null 时。

    using System;
    
    public abstract class Shape
    {
       public abstract double Area { get; }
       public abstract double Circumference { get; } 
    }
    
    public class Rectangle : Shape
    {
       public Rectangle(double length, double width) 
       {
          Length = length;
          Width = width; 
       }
    
       public double Length { get; set; }
       public double Width { get; set; }
       
       public override double Area
       { 
          get { return Math.Round(Length * Width,2); } 
       } 
       
       public override double Circumference 
       {
          get { return (Length + Width) * 2; }
       }
    }
    
    public class Square : Rectangle
    {
       public Square(double side) : base(side, side) 
       {
          Side = side; 
       }
    
       public double Side { get; set; }
    }
    
    public class Circle : Shape
    {
       public Circle(double radius) 
       {
          Radius = radius;
       } 
       
       public double Radius { get; set; }
    
       public override double Circumference
       {
          get { return 2 * Math.PI * Radius; }
       }
    
       public override double Area
       {
          get { return Math.PI * Math.Pow(Radius, 2); } 
       }
    }
    
    public class Example
    {
       public static void Main()
       {
          Shape sh = null;
          Shape[] shapes = { new Square(10), new Rectangle(5, 7),
                             sh, new Square(0), new Rectangle(8, 8),
                             new Circle(3) };
          foreach (var shape in shapes)
             ShowShapeInfo(shape);
       }
    
       private static void ShowShapeInfo(Shape sh)
       {
          switch (sh)
          {
             // Note that this code never evaluates to true.
             case Shape shape when shape == null:
                Console.WriteLine($"An uninitialized shape (shape == null)");
                break;
             case null:
                Console.WriteLine($"An uninitialized shape");
                break;
             case Shape shape when sh.Area == 0:
                Console.WriteLine($"The shape: {sh.GetType().Name} with no dimensions");
                break;
             case Square sq when sh.Area > 0:
                Console.WriteLine("Information about square:");
                Console.WriteLine($"   Length of a side: {sq.Side}");
                Console.WriteLine($"   Area: {sq.Area}");
                break;
             case Rectangle r when r.Length == r.Width && r.Area > 0:
                Console.WriteLine("Information about square rectangle:");
                Console.WriteLine($"   Length of a side: {r.Length}");
                Console.WriteLine($"   Area: {r.Area}");
                break;
             case Rectangle r when sh.Area > 0:
                Console.WriteLine("Information about rectangle:");
                Console.WriteLine($"   Dimensions: {r.Length} x {r.Width}");
                Console.WriteLine($"   Area: {r.Area}");
                break;
             case Shape shape when sh != null:
                Console.WriteLine($"A {sh.GetType().Name} shape");
                break;
             default:
                Console.WriteLine($"The {nameof(sh)} variable does not represent a Shape.");
                break;   
          }
       }
    }
    // The example displays the following output:
    //       Information about square:
    //          Length of a side: 10
    //          Area: 100
    //       Information about rectangle:
    //          Dimensions: 5 x 7
    //          Area: 35
    //       An uninitialized shape
    //       The shape: Square with no dimensions
    //       Information about square rectangle:
    //          Length of a side: 8
    //          Area: 64
    //       A Circle shape

    其它资源:

  • 相关阅读:
    main函数的一些特性
    确保函数的操作不超出数组实参的边界
    今天学习了一点sed
    libevent 与事件驱动
    mvc3 action验证失败后的自定义处理
    使用spring.net+nibernate时如何用aspnet_regiis加密数据库连接字符串
    C# 中 IList IEnumable 转换成 List类型
    Nhibernate 过长的字符串报错 dehydration property
    小论接口(interface)和抽象类(abstract class)的区别
    C# 语言在函数参数列表中出现this关键词的作用
  • 原文地址:https://www.cnblogs.com/haogj/p/7637475.html
Copyright © 2020-2023  润新知