开关/模式匹配思想

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (11)

我最近一直在研究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/etc或复合三元条件(对于非平凡表达式--括号非常混乱)的等价条件要清楚得多。它还避免了罗得,并允许将简单的扩展(直接或通过扩展方法)扩展到更特定的匹配,例如,一个InRange(...)匹配可与VB SelectCase“x to y”的用法相媲美。

我只是试图评估人们是否认为像上面这样的构造(在没有语言支持的情况下)有很多好处?

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

  • 用于评估的Func<TSource,TValue>版本--可与复合三元条件语句相比较
  • 行动<TSource>版本-可与if/Elif/Elseif/Else进行比较
  • 表达式<Func<TSource,TValue>>版本--作为第一个版本,但可由任意LINQ提供程序使用

此外,使用基于表达式的版本可以实现表达式树重写,本质上是将所有分支内联到一个复合条件表达式中,而不是使用重复调用。我最近还没有检查过,但是在一些早期实体框架构建中,我似乎记得这是必要的,因为它不太喜欢InvoationExpression。它还允许更有效地使用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));
}
用户回答回答于

扫码关注云+社区