3. C# 7 及更高版本中的函数式编码

我不确定是什么时候决定将 C# 打造成面向对象/函数式混合语言的。最早的基础工作是在 C# 3 中奠定的。当时引入了 Lambda 表达式和匿名类型等功能,这些功能后来成为 .NET 3.5 中 Linq 的一部分。

但在那之后,很长一段时间内,函数式功能方面并没有太多新东西。事实上,直到 2017 年 C# 7 发布后,函数式编程似乎才再次与 C# 团队相关。

从 C# 7 开始,每个版本的 C# 都包含一些新的和令人兴奋的东西,可以进行更多函数式编码,这一趋势目前没有任何停止的迹象!

在上一章中,我们研究了可以在几乎任何可能仍在使用的 C# 代码库中实现的函数式功能。在本章中,我们将抛弃这一假设,并研究如果您的代码库允许使用任何最新功能(或至少是自 C# 7 以来发布的功能),您可以使用的所有功能。

元组

元组是在 C#7 中引入的。Nuget 包确实存在,以允许一些旧版本的 C# 也使用它们。它们基本上是一种将属性的快速集合组合在一起的方法,而无需创建和维护类。

如果您有几个属性想要在一个地方保留一分钟,然后立即处理,那么元组非常适合。

如果您有多个要在 Select 之间传递的对象,或者有多个项目想要传入或传出,那么您可以使用元组。

这是您可能考虑使用元组进行以下操作的示例:

var filmIds = new[]
{
   
    4665,
    6718,
    7101
};

// 将 filmIds 数组中的每个 int 元素
// 转换为包含影片和演员列表的元组
// 作为单独的属性

var filmsWithCast = filmIds.Select(x => (
    film: GetFilm(x),
    castList: GetCastList(x)
));


//这里的“x”是一个元组,现在它被转换为字符串

var renderedFilmDetails = filmsWithCast.Select(x =>
                                               @$"
                                               Title: {
     x.film.Title}
                                               Director: {
     x.film.Director}
                                               Cast: {
     string.Join(", ", x.castList)}
                                               ".Trim());

在我上面的例子中,我使用 Tuple 将两个查找函数的数据与每个给定的电影 ID 配对,这意味着我可以运行后续的 Select 来将对象对简化为单个返回值。

模式匹配

Switch 语句出现的时间比现在仍在工作的开发人员的时间还要长。它们有自己的用途,但其功能非常有限。函数式编程采用了这一概念并将其提升了几个层次。这就是模式匹配。

C# 7 开始将此功能引入 C# 语言,随后在后续版本中多次增强,并且很可能将来还会添加更多功能。

模式匹配是一种节省大量工作的神奇方法。为了向您展示我的意思,我现在将向您展示一些过程代码,然后展示如何在几个不同版本的 C# 中实现模式匹配。

程序化银行账户

为了举个例子,让我们想象一下经典的面向对象工作示例之一——银行账户。我将创建一组银行账户类型,每个账户都有不同的计算利息金额的规则。这些并不是真正基于真实的银行业务,它们完全出自我的想象。

这些是我的规则:

  • 标准银行账户通过将余额乘以账户利率来计算利息
  • 余额为 10,000 或更少的高级银行账户是标准银行账户
  • 余额超过 10,000 的高级银行账户适用的利率加上额外奖励利率
  • 百万富翁的银行账户,拥有的钱多得超过了小数所能容纳的最大值(这是一个非常非常大的数字 - 大约 8*10^28,所以他们一定非常富有。如果我问他/她,你认为他/她愿意借给我一点吗?我可以买一双新鞋)。他们有一个溢出余额属性,用于添加他们拥有的所有超过最大小数值的钱,他们不能像我们这些平民一样将其存储在标准余额属性中。他们需要根据两个余额来计算利息。
  • 大富翁玩家的银行账户。他们通过考试可以额外获得 200 美元。我没有实施“直接进监狱”的逻辑,一天只有这么多小时。

这些是我的课程:

 public class StandardBankAccount
 {
   
     public decimal Balance {
    get; set; }
     public decimal InterestRate {
    get; set; }
 }

 public class PremiumBankAccount : StandardBankAccount
 {
   
     public decimal BonusInterestRate {
    get; set; }
 }

 public class MillionairesBankAccount : StandardBankAccount
 {
   
     public decimal OverflowBalance {
    get; set; }
 }

 public class MonopolyPlayersBankAccount : StandardBankAccount
 {
   
     public decimal PassingGoBonus {
    get; set; }
 }

面向对象的方法来实现这些规则 - 或者我认为是“长手”方法,可能看起来像这样:

 public decimal CalculateInterest(StandardBankAccount sba)
 {
   
   // If real type of object is PremiumBankAccount
   if (sba.GetType() == typeof(PremiumBankAccount))
   {
   
     // cast to correct type so we can access the Bonus interest
     var pba = (PremiumBankAccount)sba;
     if (pba.Balance > 10000)
     {
   
         return pba.Balance * (pba.InterestRate + pba.BonusInterestRate);
     }
   }

  // if real type of object is a Millionaire's bank account
  if(sba.GetType() == typeof(MillionairesBankAccount))
  {
   
    // cast to the correct type so we can get access to the overflow
    var mba = (MillionairesBankAccount)sba;
    return (mba.Balance * mba.InterestRate) +
             (mba.OverflowBalance * mba.InterestRate)
  }

    // if real type of object is a Monopoly Player's bank account
  if(sba.GetType() == typeof(MonopolyPlayersBankAccount))
  {
   
    // cast to the correct type so we can get access to the bonus
    var mba = (MonopolyPlayersBankAccount)sba
  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0neKing2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值