开关/模式匹配的想法
我最近一直在研究F#,尽管我不太可能马上跳过栅栏,但它肯定会突出显示C#(或库支持)可以使生活更轻松的一些领域。
特别是,我正在考虑F#的模式匹配功能,它允许使用非常丰富的语法 - 比当前的开关/条件C#等价物更具表达力。 我不会试图给出一个直接的例子(我的F#不符合它),但总之它允许:
尽管C#最终可以借用这些丰富内容,但在此期间我一直在研究在运行时可以做些什么 - 例如,将一些对象敲在一起以允许:
var getRentPrice = new Switch<Vehicle, int>()
.Case<Motorcycle>(bike => 100 + bike.Cylinders * 10) // "bike" here is typed as Motorcycle
.Case<Bicycle>(30) // returns a constant
.Case<Car>(car => car.EngineType == EngineType.Diesel, car => 220 + car.Doors * 20)
.Case<Car>(car => car.EngineType == EngineType.Gasoline, car => 200 + car.Doors * 20)
.ElseThrow(); // or could use a Default(...) terminator
getRentPrice是一个Func <Vehicle,int>。
[注意 - 也许切换/案例这里是错误的条款...但它显示了这个想法]
对我来说,这比使用重复的if / else或复合三元条件(对于非平凡表达式非常混乱 - 括号内的丰富)等价得多。 它还避免了大量的投射,并且允许简单的扩展(直接或通过扩展方法)进行更具体的匹配,例如InRange(...)匹配可与VB Select ... Case“x to y “用法。
我只是想衡量一下,如果人们认为像上面这样的构造有很多好处(在没有语言支持的情况下)?
另外请注意,我一直在玩3种以上的变体:
此外,使用基于表达式的版本可以实现表达式树重写,基本上将所有分支内联到单个复合条件表达式中,而不是使用重复的调用。 我最近没有检查,但在一些早期的Entity Framework构建中,我似乎回想起这是必要的,因为它不太喜欢InvocationExpression。 它还允许更有效地使用LINQ到对象,因为它避免了重复的委托调用 - 测试显示与上面(使用表达式表单)相同的速度执行相同的速度[事实上比同等速度的C#复合条件语句。 为了完整性,基于Func <...>的版本花了C#条件语句的4倍,但仍然非常快,并且在大多数使用情况下不太可能成为主要瓶颈。
我欢迎任何想法/输入/批评/等(关于更丰富的C#语言支持的可能性...这里希望; -p)。
我知道这是一个老话题,但在c#7中,您可以这样做:
switch(shape)
{
case Circle c:
WriteLine($"circle with radius {c.Radius}");
break;
case Rectangle s when (s.Length == s.Height):
WriteLine($"{s.Length} x {s.Height} square");
break;
case Rectangle r:
WriteLine($"{r.Length} x {r.Height} rectangle");
break;
default:
WriteLine("<unknown shape>");
break;
case null:
throw new ArgumentNullException(nameof(shape));
}
Bart De Smet的优秀博客包含8部分内容,涉及您所描述的内容。 在这里找到第一部分。
在尝试在C#中完成这些“功能”的事情(甚至尝试写一本书)之后,我得出的结论是,除了少数例外,否则这样的事情不会有太大的帮助。
主要原因是像F#这样的语言从真正支持这些功能中获得了很大的力量。 不是“你可以做到”,而是“很简单,很明显,这是预期的”。
例如,在模式匹配中,您可以让编译器告诉您是否存在不完整的匹配,或者其他匹配不会被命中。 这对于开放式类型来说不太有用,但是当匹配歧视的联合或元组时,它非常漂亮。 在F#中,你期望人们模式匹配,并且它立即有意义。
“问题”在于,一旦开始使用某些功能概念,想要继续就很自然。 但是,在C#中利用元组,函数,部分方法应用程序和currying,模式匹配,嵌套函数,泛型,monad支持等非常快,非常难看。 这很有趣,一些非常聪明的人在C#中做了一些非常酷的事情,但实际上使用它感觉很沉重。
我最终在C#中经常使用(跨项目):
**但请注意:缺少自动泛化和类型推断确实会阻碍使用这些功能。 **
所有这些都像其他人提到的那样,在一个小团队中,为了特定的目的,是的,如果你被C#困住了,也许他们可以提供帮助。 但根据我的经验,他们通常觉得比他们的价值更麻烦 - YMMV。
其他一些链接: