C# 9.0 功能預覽 (5) pattern matching

繼續說明 not patterns 和 simple type patterns。

環境
Visual Studio 2019 - 16.8.0 Preview 3.2
.NET 5.0.0-rc.1.20451.14

Not patterns 基本上用於型別的比對和 null 比對,例如:

    class Program
    {
        static void Main(string[] args)
        {
           
            foreach (var item in GetNotStudent (Create()))
            {
                Console.WriteLine(item);
            }
            
            foreach (var item in Create())
            {
                if ( item.Name is not null )
                {
                    Console.WriteLine(item.Name);
                }
            }

        }

        static IEnumerable <string> GetNotStudent(IEnumerable <IPerson> people)
        {
            return people.Where(x => x is not Student).Select(x => x.Name);
        }

        static List<IPerson> Create()
        {
            return new List<IPerson>
                   {
                       new Teacher {Name= "Bill" },
                       new Teacher {Name= "David"},
                       new Student{ Name = "魯夫",  Gender = Gender.Male , Score= 60},
                       new Student{ Name = "妮可羅賓",  Gender = Gender.Female , Score= 82},
                       new Student{ Name = "娜美",   Gender = Gender.Female, Score= 70 },
                       new Student{ Name = "騙人布" ,Gender = Gender.Male, Score= 55 },
                       new Student{ Name = "香吉士",  Gender = Gender.Male, Score= 58 },
                       new Student{ Name = "喬巴",   Gender = Gender.Male, Score= 67 },
                       new Student{ Name = "布魯克",  Gender = Gender.Male, Score= 99 },
                       new Student{ Name = "索隆",  Gender = Gender.Male, Score= 80 },
                       new Student{ Gender = Gender.Male , Score= 60},
                   };
        }
    }

    interface IPerson
    {
        Guid ID { get; set; }
        string Name { get; set; }
    }

    class Teacher : IPerson
    {
        public Guid ID { get; set; }
        public string Name { get; set; }
        public string Subject { get; set; }
    }

    class Student : IPerson
    {
        public Guid ID { get; set; }
        public string Name { get; set; }

        public bool IsPassed
        {
            get { return Score > 59; }
        }

        public Gender Gender { get; set; }

        public int Score { get; set; }
    }

    public enum Gender
    {
        Male, Female
    }

在 GetNotStudent 裡面用了 Where(x => x is not Student) 來排除屬於 Student class 的執行個體。

在 Main 中的第二個 foreach 用了 item.Name is not null 來排除 Name 屬性為 null 的資料 ( 這讓我回憶起 VB 的 IsNot 運算子)。

Simple type patterns

Simple type pattern 主要是消除在 C# 8 某些需要捨棄符號的狀況,例如以前在 C# 8 得這樣寫:

 static string GetShape(IShape shape) => shape switch
 {
     null => "null",
     Rectangle _ => "矩形",
     Circle _=> "圓形",
     _ => "不知道是啥"
 };

即使用不到,在 Rectangle 和 Circle 後方還是得加上個 _ ,在 C# 9 就可以簡化掉:

 static string GetShape(IShape shape) => shape switch
 {
     null => "null",
     Rectangle => "矩形",
     Circle => "圓形",
     _ => "不知道是啥"
 };

完整程式碼如下:

    class Program
    {
        static void Main(string[] args)
        {
            var shapes = new List<IShape>{ new Rectangle { Width = 10, Height = 10, Name ="矩形"  },
                                           new Circle { Radius = 3.2 , Name= "圓形"},
                                           new Line { Length = 4.9 , Name="直線"},
                                           null };
            foreach (var shape in shapes)
            {
                Console.WriteLine(GetShape(shape));
            }

        }

        static string GetShape(IShape shape) => shape switch
        {
            null => "null",
            Rectangle => "矩形",
            Circle => "圓形",
            _ => "不知道是啥"
        };

    }

    interface IShape
    {
        string Name { get; set; }
    }

    class Rectangle : IShape
    {
        public string Name { get; set; }

        public double Width { get; set; }

        public double Height { get; set; }

    }
    class Circle : IShape
    {
        public string Name { get; set; }

        public double Radius { get; set; }
    }

    class Line : IShape
    {
        public string Name { get; set; }

        public double Length { get; set; }
    }

點選此處看範例