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

續上集。

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

Position pattern 其實和 ValueTuple 也有點關係, 主要是應用在具有 Deconstruct 的型別。這個範例先假設有一個 Expression class,其內容包含了一個 string 型別的運算元以及兩個 double 型別的運算子 (註:為了讓運算元可以有例外的情形,所以我們很不合理的用了 string 型別來表示);而且為這個類別加入一個  Deconstruct method (解構元組方法)。

 class Expression
 {
     public Expression(string operand, double x, double y)
     {
         Operand = operand;
         X = x;
         Y = y;
     }
     public string Operand { get; }
     public double X { get;  }
     public double Y { get; }

     public void Deconstruct(out string operand, out double x, out double y)
     {
         operand = Operand;
         x = X;
         y = Y;
     }
 }

照例來一個情境設定,對於加減乘這三個操作問題通常不大,至於除法,我們設定若是除以零的狀態則回傳 Double.NaN,如果 Operand 不屬於加減乘除符號則拋出例外。接著來完成整個程式碼。

 class Program
 {
     static void Main(string[] args)
     {
         foreach (var item in CreateList())
         {
             try
             {
                 Console.WriteLine(Calculate(item));
             }
             catch (ArgumentException ex )
             {
                 Console.WriteLine(ex.Message);
             }
         }
     }

     static double Calculate(Expression expression) => expression switch
     {
         ("+", var x, var y) => x + y,
         ("-", var x, var y) => x - y,
         ("*", var x, var y) => x * y,
         ("/", _, 0) => double.NaN,
         ("/", var x, var y) => x / y,
         (_, _, _) => throw new ArgumentException("Operand should be one of +,-,*,/")
     };

     static List<Expression> CreateList() =>
         new List<Expression>
         {
             new Expression ("+", 1, 2.3),
             new Expression ("-", 14.5, 0.1),
             new Expression ("*", 8, 1.5),
             new Expression ("/", 9, 2),
             new Expression ("/", 10, 0),
             new Expression ("NotOperand", 10, 10),
         };
 }

從輸出結果可以觀察到正確的處理了new Expression ("/", 10, 0) 與 new Expression ("NotOperand", 10, 10) 這兩個物件。

對於 Calculate method 而言,傳入的本來是 Expression 型別的執行個體,理論上應該要先透過呼叫 Descontruct 產生一個 ValueTuple 再塞給 switch 的判斷條件,但是這個 position pattern 語法糖可以省略這個步驟,簡單說他就是最起碼幫你省下以下的語法:

(string s, double x, double y)  = expression;
4. property pattern

property pattern 顧名思義就是靠 proeprty 決定條件是否符合,延續使用上一個計算式的例子,但是將 Descontruct method 移除。

 class Expression
 {
     public Expression(string operand, double x, double y)
     {
         Operand = operand;
         X = x;
         Y = y;
     }
     public string Operand { get; }
     public double X { get; }
     public double Y { get; }
 }

Calculate method 應用 property pattern:

 class Program
 {
     static void Main(string[] args)
     {


         foreach (var item in CreateList())
         {
             try
             {
                 Console.WriteLine(Calculate(item));
             }
             catch (ArgumentException ex)
             {
                 Console.WriteLine(ex.Message);
             }
         }
     }

     static double Calculate(Expression expression) => expression switch
     {
         { Operand: "+", X: var x, Y: var y } => x + y,
         { Operand: "-", X: var x, Y: var y } => x - y,
         { Operand: "*", X: var x, Y: var y } => x * y,
         { Operand: "/", Y: 0 } => double.NaN,
         { Operand: "/", X: var x, Y: var y } => x / y,
         { Operand: _ } => throw new ArgumentException("Operand should be one of +,-,*,/")
     };

     static List<Expression> CreateList() =>
         new List<Expression>
         {
             new Expression ("+", 1, 2.3),
             new Expression ("-", 14.5, 0.1),
             new Expression ("*", 8, 1.5),
             new Expression ("/", 9, 2),
             new Expression ("/", 10, 0),
             new Expression ("NotOperand", 10, 10),
         };
 }

Switch expressions 就暫時介紹到此,這三集的範例程式碼在此 SwitchExpressionSamples