C# 8.0 搶先看 -- Switch expressions (1)

Switch expressions 讓 C# 的 switch statement 更方便了。

玩轉 WPF 課程招生中,傳送門https://skilltree.my/events/9cbgp

本篇文章使用環境
開發環境 Visual Studio 2019 Preview 4 (16.0.0 Preview 4)
框架       .NET Core 3.0.100-preview3-010431
編譯器    C# 8.0 beta

前幾天的文章『C# 8.0 搶先看 -- Recursive patterns』所提到的 recursive patterns 已經很狂了,switch expressions 這個新的特性也不遑多讓,

switch statement 的改變歷史應該是從 7.0 開始的,在 C# 6 以前的時代 switch  statement 是個很單純的傢伙,因為比對運算式的限制很多,基本上每個 case statement 都是互斥的;到了 C# 7.0,微軟解除了對於比對運算式的限制,在 Microsoft Docs 上有這個一句話 『 Starting with C# 7.0, the match expression can be any non-null expression. 』,也就是說任何非 null 的運算式都可以成為 switch 的比對運算式,這使得 pattern matching 可以應用在 switch statement;另外在 case statement 已經解除互斥的限制,又加上了 when clause(子句) 的語法,這些特性使得在 C# 7.0 後 switch 的應用更為靈活。

到了 C# 8.0,又添加上可以使用 expression body (運算式主體),創造出更簡潔的 switch case 語法,不囉嗦,先來看第一個範例。

先設定兩個資料型別,分別是矩形與圓形:

 class Rectangle
 {
     public double Width { get; set; }
     public double Height { get; set; }
 }

 class Circle
 {
     public double Radius { get; set; }
 }

使用以上兩個型別建立一個 List<object> 集合,循序取出這個集合的物件並且回傳其面積,若不是 Rectangle 或 Circle 的執行個體,則回傳 -1:

class Program
{
    static void Main(string[] args)
    {
        foreach (var shape in GetObjects())
        {
            Console.WriteLine(GetArea(shape));
        }
    }

    /// <summary>
    /// 依據不同形狀,設定不同面積計算方式
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    static double GetArea(object shape)
    {
        return shape switch
        {
            Rectangle r => r.Width * r.Height,
            Circle c => Math.Pow(c.Radius, 2) * Math.P
            _ => -1,
        };
    }

    /// <summary>
    /// 建立物件的集合
    /// </summary>
    /// <returns></returns>
    static List<object> GetObjects() =>
        new List<object>
        {
            new Rectangle { Width = 5, Height =5 },
            new Rectangle { Width = 15, Height =5 },
            new Circle { Radius = 6 },
            new Rectangle { Width = 5, Height =5 },
            new Circle { Radius = 10 },
        };        
}

重點在 GetArea 這個 method,C# 8.0 為 case statement 引進了 expression-bodied ,而且這個把 switch 的條件式 (就是 shape) 的順序換了一下,這個更換順序也使得整個 switch 區塊可以應用 expression-bodied method,於是就讓程式碼可以更短一些,如下:

 static double GetArea(object shape) => shape switch
 {
     Rectangle r => r.Width * r.Height,
     Circle c => Math.Pow(c.Radius, 2) * Math.PI,
     _ => -1,
 };

若是在 C# 7.x 的版本上要使用以下的寫法 :

 static double GetArea(object shape)
 {
     switch (shape)
     {
         case Rectangle r:
             return r.Width * r.Height;
         case Circle c:
             return Math.Pow(c.Radius, 2) * Math.PI;
         default:
             return -1;
     }
 }

註:如果是 C# 6 及其以下的版本,硬要用 switch statement 解這個問題就會寫出極為醜陋又不穩固的程式碼了,在這個情況下,用 if statement 都來得比 switch statement 好。

此篇先介紹基本語法,下一篇來聊其他的相關應用變化。