为了账号安全,请及时绑定邮箱和手机立即绑定

开关/模式匹配的想法

开关/模式匹配的想法

C#
凤凰求蛊 2019-10-05 13:31:00
我最近一直在研究F#,虽然我不太可能很快就克服障碍,但它无疑突出了C#(或库支持)可以使生活更轻松的某些领域。特别是,我正在考虑F#的模式匹配功能,该功能允许使用非常丰富的语法-比当前的switch / conditional 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>。[注意-也许这里的Switch / Case是错误的术语...但是它表明了这个主意]对我来说,这比使用重复的if / else或复合三元条件(对于非平凡的表达式会变得非常混乱-方括号)更加清楚。它还避免了很多转换,并允许简单地扩展(直接或通过扩展方法)到更特定的匹配项,例如,与VB Select ... Case相当的InRange(...)匹配项。 ”的用法。我只是在尝试衡量人们是否认为上述结构(在没有语言支持的情况下)有很多好处?另外请注意,我一直在使用上述3种变体:用于评估的Func <TSource,TValue>版本-与复合三元条件语句相当一个Action <TSource>版本-与if / else if / else if / else if / else相当一个Expression <Func <TSource,TValue >>版本-作为第一个版本,但可由任意LINQ提供程序使用此外,使用基于表达式的版本可以重写表达式树,实质上是将所有分支内联到单个复合条件表达式中,而不是使用重复调用。我最近没有检查过,但是在某些早期的Entity Framework构建中,我似乎想起来这是必要的,因为它不太喜欢InvocationExpression。由于它避免了重复的委托调用,因此还允许更高效地使用LINQ-to-Objects-测试显示,与上述C#相比,上述匹配(使用Expression形式)以相同的速度(实际上要快得多)执行匹配复合条件语句。为了完整起见,基于Func <...>的版本花费的时间是C#条件语句的4倍,但仍非常快,并且在大多数用例中不太可能成为主要瓶颈。我欢迎上面的任何想法/输入/批评/等等(或关于更丰富的C#语言支持的可能性...这里希望;-p)。
查看完整描述

3 回答

?
BIG阳

TA贡献1859条经验 获得超6个赞

我知道这是一个老话题,但是在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));

}


查看完整回答
反对 回复 2019-10-05
?
FFIVE

TA贡献1797条经验 获得超6个赞

尝试在C#中完成此类“功能性”事情(甚至尝试编写一本书)之后,我得出的结论是,除了少数例外,此类事情没有太大帮助。


主要原因是诸如F#之类的语言通过真正支持这些功能而获得了强大的功能。不是“您可以做到”,而是“这很简单,很明显,很期待”。


例如,在模式匹配中,编译器会告诉您是否存在不完整的匹配,或者何时永远不会再匹配其他匹配。这对于开放式类型不太有用,但是当与已区分的联合或元组匹配时,它非常漂亮。在F#中,您希望人们进行模式匹配,并且这立即有意义。


“问题”是,一旦您开始使用某些功能概念,就自然会继续。但是,在C#中利用元组,函数,部分方法应用程序和currying,模式匹配,嵌套函数,泛型,monad支持等变得非常丑陋,非常迅速。这很有趣,并且一些非常聪明的人在C#中做了一些很酷的事情,但是实际上使用它感觉很沉重。


我最终在C#中经常使用的内容(跨项目):


序列函数,通过IEnumerable的扩展方法。诸如ForEach或Process之类的东西(“ Apply”?–对序列项进行操作,就像枚举一样)适合,因为C#语法很好地支持了它。

抽象常见的语句模式。复杂的try / catch / finally块或其他涉及的(通常是非常通用的)代码块。扩展LINQ-to-SQL也适用于此。

元组,在某种程度上。

**但请注意:缺乏自动归纳和类型推断确实阻碍了甚至使用这些功能。**


正如其他人所提到的,所有这些都是在一个小型团队中,出于特定目的,是的,如果您坚持使用C#,也许他们可以提供帮助。但是以我的经验,他们通常感到比他们值得的麻烦更多-YMMV。


查看完整回答
反对 回复 2019-10-05
  • 3 回答
  • 0 关注
  • 314 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信