續上集。
開發環境 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
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;
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 。