首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >这种切换/模式匹配的想法有什么好处吗?

这种切换/模式匹配的想法有什么好处吗?
EN

Stack Overflow用户
提问于 2008-10-01 06:34:13
回答 10查看 24.6K关注 0票数 158

我最近一直在关注F#,虽然我不太可能在短期内越过栅栏,但它肯定突出了C# (或库支持)可以让生活变得更容易的一些领域。

特别是,我正在考虑F#的模式匹配功能,它允许非常丰富的语法-比当前的switch/conditional C#等价物更具表现力。我不会尝试给出一个直接的例子(我的F#不能胜任),但简而言之,它允许:

  • match by type (通过对区分的联合进行全覆盖检查)注意:这也推断出绑定变量的类型,给出成员访问etc
  • match by
  • of上述(可能还有其他一些我不知道的场景)

虽然对于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。

注意--这里的Switch/Case可能是错误的术语...但它表明了这个想法

对我来说,这比使用重复的if/else或复合三元条件(对于非平凡的表达式会变得非常混乱-括号中有很多)的等价物要清楚得多。它还避免了大量的强制转换,并允许对更具体的匹配进行简单的扩展(直接或通过扩展方法),例如InRange(...)匹配相当于VB Select...Case "x to y“的用法。

我只是想知道人们是否认为像上面这样的构造(在缺乏语言支持的情况下)有很多好处?

另外请注意,我一直在尝试上面的3种变体:

用于评估的

  • a Func版本-可与复合三元条件LINQ操作版本相媲美-可与if/else if/else
  • an Expression>版本相媲美-作为第一个版本,但可由任意LINQ providers

使用

此外,使用基于表达式的版本可以重写表达式树,本质上是将所有分支内联到单个复合条件表达式中,而不是使用重复调用。我最近没有检查过,但在一些早期的实体框架构建中,我似乎记得这是必要的,因为它不太喜欢InvocationExpression。它还允许更有效地使用LINQ- to -Objects,因为它避免了重复的委托调用-测试显示,与等效的C#复合条件语句相比,上面的匹配(使用表达式形式)的执行速度要快一些。在完整性方面,基于Func<...>的版本花费的时间是C#条件语句的4倍,但仍然非常快,在大多数用例中不太可能成为主要的瓶颈。

我欢迎任何关于以上(或关于更丰富的C#语言支持的可能性)的想法/意见/批评/等等。希望如此;-p)。

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2017-12-13 22:18:13

在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));
}
票数 23
EN

Stack Overflow用户

发布于 2008-10-12 11:38:25

在尝试用C#做这样的“函数式”事情(甚至尝试写一本关于它的书)之后,我得出的结论是:不,除了少数例外,这样的事情没有太大帮助。

主要原因是像F#这样的语言从真正支持这些特性中获得了很大的力量。不是“你能做到”,而是“这很简单,很清楚,这是意料之中的”。

例如,在模式匹配中,编译器会告诉您是否存在不完整的匹配,或者何时永远不会命中另一个匹配。这对于开放式类型用处不大,但是当匹配有区别的联合或元组时,它非常有用。在F#中,您希望人们进行模式匹配,这立即就有意义了。

“问题”是,一旦你开始使用一些函数式概念,自然会想要继续下去。然而,在C#中利用元组、函数、分部方法应用程序和货币、模式匹配、嵌套函数、泛型、monad支持等变得非常丑陋,而且速度非常快。它很有趣,一些非常聪明的人在C#中做了一些非常酷的事情,但实际上使用它感觉很重。

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

  • 序列函数,通过IEnumerable的扩展方法实现。ForEach或Process ("Apply"?--在枚举序列项时对其执行操作)之类的语句也适用,因为C#语法支持well.
  • Abstracting公共语句模式。复杂的try/catch/finally代码块或其他涉及的(通常是高度泛型的)代码块。扩展LINQ-to-SQL也适用于此。在某种程度上,
  • 元组。

**但请注意:缺乏自动泛化和类型推断确实阻碍了这些功能的使用。**

正如其他人提到的,在一个小团队中,出于特定的目的,是的,如果你坚持使用C#,也许它们可以帮助你。但在我的经验中,它们通常感觉比它们的价值更麻烦- YMMV。

其他一些链接:

票数 37
EN

Stack Overflow用户

发布于 2008-10-01 07:59:57

可以说,C#没有使类型切换变得简单的原因是因为它主要是一种面向对象的语言,而在面向对象的术语中实现这一点的“正确”方法是在Vehicle上定义一个GetRentPrice方法,并在派生类中覆盖它。

也就是说,我花了一些时间尝试像F#和Haskell这样的具有这种功能的多范式和函数式语言,我遇到过许多以前它会很有用的地方(例如,当你不是在编写需要切换的类型时,所以你不能在它们上实现一个虚拟方法),这是我欢迎进入语言的东西,以及有区别的联合。

编辑:删除了有关性能的部分,因为Marc表示它可能会短路

另一个潜在的问题是可用性问题--从最终的调用中可以清楚地看出,如果匹配不满足任何条件会发生什么,但如果匹配两个或更多条件,会发生什么行为呢?它应该抛出一个异常吗?应该返回第一个匹配项还是最后一个匹配项?

我倾向于用来解决这类问题的一种方法是使用字典字段,类型作为键,lambda作为值,这对于使用对象初始化器语法构造非常简洁;但是,这只考虑了具体类型,不允许附加谓词,因此可能不适用于更复杂的情况。附注-如果您查看C#编译器的输出,它会频繁地将switch语句转换为基于字典的跳转表,因此似乎没有充分的理由不支持类型切换

票数 25
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/156467

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档