c# switch / case extra variable syntax

10 浏览
0 Comments

c# switch / case extra variable syntax

最近我一直在研究F#,虽然我不太可能很快转到F#,但它确实突显出C#(或库支持)可以让生活更轻松的一些领域。

特别是,我在考虑F#的模式匹配能力,它允许非常丰富的语法,比当前的C# switch/条件语句更具表达力。我不会给出直接的示例(因为我的F#还不够好),但简而言之,它可以实现:

  • 按类型匹配(对于可辨别联合类型,还会进行全覆盖检查)[注意,这也推断了绑定变量的类型,可以进行成员访问等操作]
  • 按条件匹配
  • 以上两者的组合(以及可能其他我不知道的场景)

虽然让C#最终借用一些这样的特性会很棒,但在此期间,我一直在研究运行时可以做什么-例如,很容易组合一些对象来实现以下功能:

var getRentPrice = new Switch()
        .Case(bike => 100 + bike.Cylinders * 10) // 这里的"bike"被定义为Motorcycle类型
        .Case(30) // 返回一个常量
        .Case(car => car.EngineType == EngineType.Diesel, car => 220 + car.Doors * 20)
        .Case(car => car.EngineType == EngineType.Gasoline, car => 200 + car.Doors * 20)
        .ElseThrow(); // 或者可以使用Default(...)终止符

其中getRentPrice是一个Func类型的函数。

[注意-也许这里的Switch/Case不是正确的术语...但它展示了这个想法]

对我来说,这比使用重复的if/else或复合的三元条件表达式要清晰得多(对于非平凡表达式来说,三元条件表达式会非常混乱-括号无处不在)。它还避免了许多强制转换,并允许简单的扩展(直接或通过扩展方法)到更具体的匹配,例如与VB的Select...Case "x To y"用法相似的InRange(...)匹配。

我只是想了解人们是否认为在缺乏语言支持的情况下,像上述的结构有很多好处?

此外,我还尝试了上述的3个变体:

  • 一个Func版本用于评估-类似于复合三元条件语句
  • 一个Action版本-类似于if/else if/else if/else if/else
  • 一个Expression>版本-与第一个版本相同,但可由任意LINQ提供程序使用

此外,使用基于表达式的版本可以进行表达式树重写,将所有分支内联到单个复合条件表达式中,而不是重复调用。我没有最近检查过,但我记得在一些早期的Entity Framework版本中,这是必需的,因为它对InvocationExpression不太友好。它还可以更有效地在LINQ-to-Objects中使用,因为它避免了重复的委托调用-测试显示使用Expression形式的匹配与等效的C#复合条件语句的速度相同(实际上稍微快一些)。为了完整起见,基于Func<...>的版本比C#条件语句慢4倍,但仍然非常快,并且在大多数用例中不太可能成为主要瓶颈。

对于上述内容(或关于更丰富的C#语言支持的可能性)我欢迎任何想法/输入/批评等。希望能有更丰富的C#语言支持。

0
0 Comments

C#中没有简单地支持根据类型进行switch的原因可能是因为它主要是一种面向对象的语言,按照面向对象的方式,应该在Vehicle上定义一个GetRentPrice方法,并在派生类中进行重写。

然而,我花了一些时间来尝试使用F#和Haskell等多范式和函数式语言,这些语言具有这种类型的能力,并且我在以前的一些地方发现这将是有用的(例如,当您不能为需要切换的类型实现虚拟方法时),这是我希望在语言中引入的功能之一,同时还有辨别联合。

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

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

实际上 - 我的版本在委托和表达式版本中都进行了短路。表达式版本编译为复合条件;委托版本只是一组谓词和函数/操作 - 一旦匹配到了就停止。

有趣的是 - 从粗略的观察中,我认为它必须至少对每个条件进行基本检查,因为它看起来像是一个方法链,但现在我意识到这些方法实际上是将一个对象实例链接在一起构建的,所以您可以这样做。我将编辑我的答案以删除该语句。

0
0 Comments

C# 7引入了一种新的switch/case语法,允许在case块中使用额外的变量。在之前的版本中,case块只能匹配常量表达式。这种新的语法使得模式匹配更加强大和灵活。

在给定的代码示例中,我们可以看到在switch语句中的每个case块都使用了不同的模式匹配。例如,第一个case块使用了类型模式匹配,并将变量c声明为Circle类型。第二个case块使用了条件模式匹配,并将变量s声明为Rectangle类型,并检查其长度和高度是否相等。第三个case块使用了类型模式匹配,并将变量r声明为Rectangle类型。

这种新的语法的出现原因是为了增强C#中的模式匹配功能,使其更接近函数式编程语言F#中的模式匹配。与F#相比,C#的模式匹配更加完整,因为它需要覆盖所有可能的情况,并且在没有完全描述的情况下会由编译器发出警告。这种新的语法使得在switch语句中进行模式匹配更加方便和直观。

要解决这个问题,我们只需要使用C# 7中的新语法,使用冒号(:)后面的模式匹配。在每个case块中,我们可以声明一个新的变量,并将其与模式匹配相结合。这使得我们可以更方便地处理不同的情况,并且可以在匹配的情况下使用额外的变量。

总之,C# 7中引入的这种switch/case额外变量语法是为了增强模式匹配功能,使其更接近函数式编程语言F#中的模式匹配。它允许我们在case块中声明额外的变量,并将其与模式匹配相结合。这种新的语法使得模式匹配更加强大和灵活,提高了代码的可读性和可维护性。

0
0 Comments

C#中的switch / case语句中的附加变量语法是指在case语句中使用额外的变量。这种语法的出现是因为在使用函数式概念时,人们自然而然地想要继续使用这种语法。然而,在C#中,使用元组、函数、部分方法应用和柯里化、模式匹配、嵌套函数、泛型和单子支持等函数式概念会变得非常复杂和丑陋。尽管在C#中可以实现这些功能,但实际上使用起来感觉很繁重。

在C#中,有一些功能可以经常使用:

- 使用IEnumerable的扩展方法来实现序列函数,例如ForEach或Process。C#的语法很好地支持这些功能。

- 抽象常见的语句模式,例如复杂的try/catch/finally块或其他复杂的代码块。这里也包括扩展LINQ-to-SQL。

- 在某种程度上使用元组。

但需要注意的是,缺乏自动泛化和类型推断的特性限制了这些功能的使用。

总结起来,在小团队、特定目的下,也许这些功能可以帮助解决C#中的问题。但根据我的经验,它们通常带来的麻烦比它们的价值更大。

0