C# 6 元组应用 Part 2:C# 也玩模式匹配
C# 7给我们带来了一个半吊子的 switch 语句模式匹配,只能简单的匹配类型而已,完全没有什么用处。这里我提供个更好的简单实现,用 C# 6 的 ValueTuple 模拟函数式语言的模式匹配功能。
首先就是实现:
1 public static class ValueTupleExtensions 2 { 3 4 /// <summary> 5 /// 至少匹配一个条件 6 /// </summary> 7 /// <typeparam name="T"></typeparam> 8 /// <param name=""></param> 9 /// <returns></returns> 10 public static TResult MatchOne<TResult>(params (Func<bool> condExpr, Func<TResult> resultExpr)[] pairs) 11 { 12 foreach (var pair in pairs) 13 { 14 if (pair.condExpr()) 15 { 16 return pair.resultExpr(); 17 } 18 } 19 throw new InvalidOperationException("无匹配的表达式"); 20 } 21 22 /// <summary> 23 /// 匹配默认或指定的条件 24 /// </summary> 25 /// <typeparam name="TResult"></typeparam> 26 /// <param name="defaultMatch"></param> 27 /// <param name="matchs"></param> 28 /// <returns></returns> 29 public static TResult MatchOneOrDefault<TResult>( 30 Func<TResult> defaultMatchExpr, 31 params (Func<bool> condExpr, Func<TResult> resultExpr)[] matchs) 32 { 33 foreach (var pair in matchs) 34 { 35 if (pair.condExpr()) 36 { 37 return pair.resultExpr(); 38 } 39 } 40 41 return defaultMatchExpr(); 42 } 43 44 public static TOutput MatchOne<TInput, TOutput>(TInput inputValue, params (TInput matcheValue, Func<TOutput> resultValueExpr)[] pairs) 45 where TInput : IEquatable<TInput> 46 { 47 foreach (var pair in pairs) 48 { 49 if (inputValue.Equals(pair.matcheValue)) 50 { 51 return pair.resultValueExpr(); 52 } 53 } 54 55 throw new InvalidOperationException("无匹配的值"); 56 } 57 58 public static TOutput MatchOneOrDefault<TInput, TOutput>(TInput inputValue, params (TInput matcheValue, Func<TOutput> resultValueExpr)[] pairs) 59 where TInput : IEquatable<TInput> 60 { 61 if (inputValue == null) 62 { 63 throw new ArgumentNullException(nameof(inputValue)); 64 } 65 66 foreach (var pair in pairs) 67 { 68 if (pair.matcheValue == null) 69 { 70 throw new ArgumentNullException(nameof(pairs)); 71 } 72 73 if (inputValue.Equals(pair.matcheValue)) 74 { 75 return pair.resultValueExpr(); 76 } 77 } 78 return default(TOutput); 79 } 80 }
然后用起来就非常简单了,首先使用 `using static` 引入静态函数:
using static ValueTupleExtensions;
然后我们实际操练下:
class Program { static void Main(string[] args) { var a = 5; //最简单的重载,与某个值相等就执行后面的 lambda 表达式 var matched = MatchOne( a, (1, () => "111"), (5, () => "555") ); Console.WriteLine($"matched={matched}"); //更自由的形式,第一个 lambda 相当于 if matched = MatchOne( (() => a == 1, () => "111"), (() => a == 5, () => "555") ); Console.WriteLine($"matched={matched}"); Console.ReadKey(); } }
虽然括号略多,不过还是很好玩的吧。
Have fun!