这个开关/模式匹配的想法有什么好处吗? [英] Is there any benefit to this switch / pattern matching idea?

查看:45
本文介绍了这个开关/模式匹配的想法有什么好处吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在研究F#,虽然我不太可能很快就克服障碍,但它无疑突显了C#(或库支持)可以使生活更轻松的某些领域.

I've been looking at F# recently, and while I'm not likely to leap the fence any time soon, it definitely highlights some areas where C# (or library support) could make life easier.

特别是,我正在考虑F#的模式匹配功能,该功能允许非常丰富的语法-比当前的switch/conditional C#等效项更具表现力.我不会尝试举一个直接的例子(我的F#不够用),但总而言之,它允许:

In particular, I'm thinking about the pattern matching capability of F#, which allows a very rich syntax - much more expressive than the current switch/conditional C# equivalents. I won't try to give a direct example (my F# isn't up to it), but in short it allows:

  • 按类型进行匹配(对有区别的联合进行全覆盖检查)[请注意,这还可以推断出绑定变量的类型,为成员提供访问权限等]
  • 谓词匹配
  • 上述(以及我可能不知道的其他一些情况)的组合

虽然C#最终借用[ahem]一些丰富的内容是很可爱的,但在此期间,我一直在研究可以在运行时完成的工作-例如,将某些对象组合在一起相当容易允许:

While it would be lovely for C# to eventually borrow [ahem] some of this richness, in the interim I've been looking at what can be done at runtime - for example, it is fairly easy to knock together some objects to allow:

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>.

where getRentPrice is a Func<Vehicle,int>.

[注意-也许这里的Switch/Case是错误的术语...但是它表明了这个主意]

[note - maybe Switch/Case here is the wrong terms... but it shows the idea]

对我来说,这比使用重复if/else或复合三元条件(对于非平凡表达式而言非常混乱-方括号)更加等效.它还避免了 lot 的转换,并允许简单扩展(直接或通过扩展方法)扩展到更特定的匹配项,例如,与VB Select相当的InRange(...)匹配项...使用"x到y"的情况.

To me, this is a lot clearer than the equivalent using repeated if/else, or a composite ternary conditional (which gets very messy for non-trivial expressions - brackets galore). It also avoids a lot of casting, and allows for simple extension (either directly or via extension methods) to more-specific matches, for example an InRange(...) match comparable to the VB Select...Case "x To y" usage.

我只是想衡量人们是否认为上述结构(在没有语言支持的情况下)有很多好处?

另外请注意,我一直在玩上述的3种变体:

Note additionally that I've been playing with 3 variants of the above:

  • 一个Func< TSource,TValue>评估版本-与复合三元条件语句相当
  • Action< TSource>版本-相当于if/else if/else if/else if/else
  • < Func< TSource,TValue>>版本-作为第一个版本,但可被任意LINQ提供程序使用
  • a Func<TSource,TValue> version for evaluation - comparable to composite ternary conditional statements
  • an Action<TSource> version - comparable to if/else if/else if/else if/else
  • an Expression<Func<TSource,TValue>> version - as the first, but usable by arbitrary LINQ providers

此外,使用基于表达式的版本可以重写表达式树,实质上将所有分支内联到单个复合条件表达式中,而不是使用重复调用.我最近没有检查过,但是在某些早期的Entity Framework构建中,我似乎想起来这是必要的,因为它不太喜欢InvocationExpression.它还可以更高效地使用LINQ-to-Objects,因为它避免了重复的委托调用-测试显示,与上述C#相比,上述匹配(使用Expression形式)以相同的速度[实际上更快地]进行了匹配.复合条件语句.为了完整起见,Func ...基于版本的时间是C#条件语句的四倍,但仍然非常快,并且在大多数用例中不太可能成为主要瓶颈.

Additionally, using the Expression-based version enables Expression-tree re-writing, essentially inlining all the branches into a single composite conditional Expression, rather than using repeated invocation. I haven't checked recently, but in some early Entity Framework builds I seem to recall this being necessary, as it didn't like InvocationExpression very much. It also allows more efficient usage with LINQ-to-Objects, since it avoids repeated delegate invocations - tests show a match like the above (using the Expression form) performing at the same speed [marginally quicker, in fact] compared to the equivalent C# composite conditional statement. For completeness, the Func<...> based-version took 4 times as long as the C# conditional statement, but is still very quick and is unlikely to be a major bottleneck in most use-cases.

我欢迎您对以上内容(或有关更丰富的C#语言支持的可能性,在此表示希望;-p)进行任何想法/输入/批评/等等.

I welcome any thoughts / input / critique / etc on the above (or on the possibilities of richer C# language support... here's hoping ;-p).

推荐答案

在C#7中,您可以执行以下操作:

In C# 7, you can do:

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));
}

这篇关于这个开关/模式匹配的想法有什么好处吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆