请选择 进入手机版 | 继续访问电脑版

[C#教程] C#9特性record 范例 、模式匹配、init 属性详情

[复制链接]
查看132 | 回复21 | 2021-9-14 11:09:24 | 显示全部楼层 |阅读模式
目次

C#的特性record 范例 、模式匹配、init 属性

一、record 范例

record ,我还是用原词吧,我知道有翻译为“记录范例 ”的说法。只是,只是,老周老以为 这不太好听,但是 老周也找不出更好的词语,还是用回 record吧。

  1. record
复制代码
  1. 引用类型
复制代码
,跟 class 很像(确实差不多)。那么,用人民群众都熟悉 的 class 不香吗,为何要新增个 record 呢?答:为了数据比较的便捷。

不明白 ?没事,往下看。迩来 有一位热心邻人 送了老周一只宠物:

  1. public class Cat
  2. {
  3. public string Nick { get; set; }
  4. public string Name { get; set; }
  5. public int Age { get; set; }
  6. }
复制代码

这只新宠物可不简单,一顶一的高级吃货。鱼肉、猪肉、鸡腿、饼干、豆腐、面包、水果、面条、小麦、飞蛾……反正,只要它能塞进嘴里的,它都吃。

接下来,我们 new 两个宠物实例。

  1. // 两个实例描述的是同一只猫
  2. Cat pet1 = new Cat
  3. {
  4. Nick = "松子",
  5. Name = "Jack",
  6. Age = 1
  7. };
  8. Cat pet2 = new Cat
  9. {
  10. Nick = "松子",
  11. Name = "Jack",
  12. Age = 1
  13. };
  14. // 居然不是同一只猫
  15. Console.WriteLine("同一只?{0}", pet1 == pet2);
复制代码

着实 ,两个实例形貌 的都是我家的乖乖。但是 ,输出的是:

  1. 同一只?False
复制代码

这是由于 ,在相称 比较时,人家关心的范例 引用——引用的是否为同一个实例。但是,在数据处理方案中,我们更关注对象中的字段/属性是否相称 ,即内容比较。

如今 ,把 Cat 的声明改为 record 范例 。

  1. public record Cat
  2. {
  3. public string Nick { get; set; }
  4. public string Name { get; set; }
  5. public int Age { get; set; }
  6. }
复制代码

然后同样用上面的 pet1 和 pet2 实例举行 相称 比较,得到预期的结果 :

  1. 同一只?True
复制代码

record 范例 让你省去了重写相称 比较(重写 Equals、GetHashCode 等方法或重载运算符)的逻辑。

实际 上,代码在编译后 record 范例 也是一个类,但自动 实现了成员相称 比较的逻辑。从前 你要手动去折腾的事如今 全交给编译器去干。

假如,有一个 User 范例 ,用于表示用户信息(包括用户名、暗码 ),然后这个 User 范例 在数据处理方案中大概 会产生N多个实例。比方 你根据条件从EF模子 中筛选出一个 User 实例 A,根据用户输入的登录名和暗码 产生了 User 实例 B。为了验证用户输入的登录信息是否精确 ,假如 User 是 class,你大概 要如许 判断 :

  1. if(A.UserName == B.UserName && A.Password == B.Password)
  2. {
  3. ..................
  4. }
复制代码

但要是你把 User 定义为 record 范例 ,那么,一句话的工夫:

  1. A == B
复制代码

二、模式匹配(Pattern Matching)

"模式匹配"这个翻译感觉怪怪滴,老周还没想出什么更好的词语。模式匹配并不是什么神奇的东西,它只是在对变量值举行 检测时的扩展举动 。从前 ,老感觉C++/C# 的 switch 语句不够强大 ,由于 传统的用法内里 ,每个 case 子句只能比较单个常量值。比如


          

  1. int 考试成绩 = 85;
  2. switch (考试成绩)
  3. {
  4. case 10:
  5. Console.WriteLine("才考这么点破分啊");
  6. break;
  7. case 50:
  8. Console.WriteLine("还差一点,就合格了");
  9. break;
  10. case 85:
  11. Console.WriteLine("真是秀");
  12. break;
  13. case 90:
  14. Console.WriteLine("奇迹发生");
  15. break;
  16. }
复制代码

我幻想着,要是能像下面如许 写就好了:

  1. switch (考试成绩)
  2. {
  3. case 0:
  4. Console.WriteLine("缺考?");
  5. break;
  6. case > 0 && <= 30:
  7. Console.WriteLine("太烂了");
  8. break;
  9. case > 30 && < 60:
  10. Console.WriteLine("还是不行");
  11. break;
  12. case >= 60 && < 80:
  13. Console.WriteLine("还得努力");
  14. break;
  15. case >= 80 && < 90:
  16. Console.WriteLine("秀儿,真优秀");
  17. break;
  18. case >= 90 && <= 100:
  19. Console.WriteLine("不错,奇迹");
  20. break;
  21. }
复制代码

等了很多年很多年(“千年等一回,等……”)以后,终于可以实现了。

  1. switch (考试成绩)
  2. {
  3. case 0:
  4. Console.WriteLine("缺考?");
  5. break;
  6. case > 0 and <= 30:
  7. Console.WriteLine("太烂了");
  8. break;
  9. case > 30 and < 60:
  10. Console.WriteLine("还是不行");
  11. break;
  12. case >= 60 and < 80:
  13. Console.WriteLine("还得努力");
  14. break;
  15. case >= 80 and < 90:
  16. Console.WriteLine("秀儿,真优秀");
  17. break;
  18. case >= 90 and <= 100:
  19. Console.WriteLine("不错,奇迹");
  20. break;
  21. }
复制代码

偶尔 间 ,不仅要检测对象的值,还得深入到其成员。比如下面这个例子,Order类表示一条订单信息。

  1. public class Order
  2. {
  3. public int ID { get; set; }
  4. public string Company { get; set; }
  5. public string ContactName { get; set; }
  6. public float Qty { get; set; }
  7. public decimal UP { get; set; }
  8. public DateTime Date { get; set; }
  9. }
复制代码

前不久,公司接到一笔Order,做成了收益应该不错。

  1. Order od = new Order
  2. {
  3. ID = 11,
  4. Company = "大嘴狗贸易有限公司",
  5. ContactName = "陈大爷",
  6. Qty = 425.12f,
  7. UP = 1000.55M,
  8. Date = new(2020, 10, 27)
  9. };
复制代码

假如我要在变量 od 上做 switch,看看,就如许 :

  1. switch (od)
  2. {
  3. case { Qty: > 1000f }:
  4. Console.WriteLine("发财了,发财了");
  5. break;
  6. case { Qty: > 500f }:
  7. Console.WriteLine("好家伙,年度大订单");
  8. break;
  9. case { Qty: > 100f }:
  10. Console.WriteLine("订单量不错");
  11. break;
  12. }
复制代码

咦?这,这是什么鬼?莫惊莫惊,这不是鬼。它的意思是判断 Qty 属性的值,假如 订单货量大于 100 就输出“订单量不错”;要是订单货量大于 1000,那就输出“发财了,发财了”。

但你会说,这对大括号怎么来的呢?还记得这种 LINQ 的写法吗?

  1. from x in ...
  2. where x.A ...
  3. select new {
  4. Prop1 = ...,
  5. Prop2 = ...,
  6. ................
  7. }
复制代码

new { ... } 是匿名范例 实例,那假如 黑白 匿名范例 呢,看看前面的 Cat 实例初始化。

  1. Cat {
  2. ..........
  3. }
复制代码

这就对了,这对大括号就是构造某实例的成员值用的,以是 ,上面的 switch 语句着实 是如许 写的:

  1. switch (od)
  2. {
  3. case Order{ Qty: > 1000f }:
  4. Console.WriteLine("发财了,发财了");
  5. break;
  6. case Order{ Qty: > 500f }:
  7. Console.WriteLine("好家伙,年度大订单");
  8. break;
  9. case Order{ Qty: > 100f }:
  10. Console.WriteLine("订单量不错");
  11. break;
  12. }
复制代码

Order{ ... } 就是匹配一个 Order 对象实例,并且它的 Qty 属性要符合 ... 条件。由于变量 od 始终就是 Order 范例 ,以是 ,case 子句中的 Order 就省略了,变成

  1. case { Qty: > 1000f }:
  2. Console.WriteLine("发财了,发财了");
  3. break;
复制代码

假如 出现多个属性,则表示为多个属性设定匹配条件,它们之间是“且”的关系。比如

  1. case { Qty: > 100f, Company: not null }:
  2. Console.WriteLine("订单量不错");
  3. break;
复制代码

猜猜啥意思?这个是可以“望文生义”的,Qty 属性的值要大于 100,并且 Company 属性的值不能为 null。不为 null 的写法是 not null,不要写成 !null,由于 如许 太丢脸 了。

假如 你的代码分支较少,你可以用 if 语句的,只是得共同 is 运算符。

  1. if (od is { UP: < 3000M })
  2. {
  3. Console.WriteLine("报价不理想");
  4. }
复制代码

但是,这个写法如今 有范围 性,它只能用常量值来做判断 ,你要是如许 写就会报错。

  1. if (od is { Date: < DateTime.Now })
  2. {
  3. ................
  4. }
复制代码

DateTime.Now 不是常量值,上面代码无法通过编译。

is 运算符从前 是用来匹配范例 的,上述的用法是它的语法扩展。

  1. object n = 5000000L;
  2. if(n is long)
  3. {
  4. Console.WriteLine("它是个长整型");
  5. }
复制代码

进化之后的 is 运算符也可以如许 用:

  1. object n = 5000000L;
  2. if(n is long x)
  3. {
  4. Console.WriteLine("它是个长整型,存放的值是:{0}", x);
  5. }
复制代码

假如 你在 if 语句内要使用 n 的值,就可以趁便 转为 long 范例 并赋值给变量 x,如许 就一步到位,不必再去写一句 long x = (long)n 。

假如 switch... 语句在判断 之后必要 返回一个值,还可以把它变成表达式来用。咱们把前面的 Order 例子改一下。

  1. string message = od switch
  2. {
  3. { Qty: > 1000f } => "发财了",
  4. { Qty: > 500f } => "年度大订单",
  5. { Qty: > 100f } => "订单量不错",
  6. _ => "未知"
  7. };
  8. Console.WriteLine(message);
复制代码

这时间 你得注意 :

  1. switch 如今 是表达式,不是语句块,以是 末了 大括号右边的分号不能少;
  2. 由于 switch 成了表达式,就不能用 case 子句了,以是 直接用详细 的内容来匹配;
  3. 末了 返回“未知”的谁人 下划线(_),也就是所谓的“弃婴”,哦不,是“弃元”,就是固然 赋了值但不必要 使用 的变量,可以直接丢掉。这里就相称 于 switch 语句块中的 default 子句,当前面全部 条件都不能匹配时,就返回“未知”。

三、属性的 init 访问器

要起首 得知道,这个 init 只用于只读属性的初始化阶段,对于可读可写的属性,和从前 一样,直接

  1. get
复制代码
;
  1. set
复制代码
; 即可。

有人说这个 init 不知干啥用,那好,咱们先不说它,先来看看 C# 前些版本中新增的属性初始化语句。

  1. public class Dog
  2. {
  3. public int No { get; } = 0;
  4. public string Name { get; } = "no name";
  5. public int Age { get; } = 1;
  6. }
复制代码

你看,如许 就可以给属性分配初始值了,那还要 init 干吗呢?

好,我给你制造一个题目 ——我要是如许 初始化 Dog 类的属性,你试试看。

  1. Dog x = new Dog
  2. {
  3. No = 100,
  4. Name = "吉吉",
  5. Age = 4
  6. };
复制代码

试一下,编译会出错吧。

C#9特性record 范例
、模式匹配、init 属性详情

有些环境 ,你可以在属性定义阶段分配初始值,但有些时间 ,你必须要在代码中初始化。在过去,我们会通过定义带参数的构造函数来办理 。

  1. public class Dog
  2. {
  3. public int No { get; } = 0;
  4. public string Name { get; } = "no name";
  5. public int Age { get; } = 1;
  6. public Dog(int no, string name, int age)
  7. {
  8. No = no;
  9. Name = name;
  10. Age = age;
  11. }
  12. }
复制代码

然后,如许 初始化。

  1. Dog x = new(1001, "吉吉", 4);
复制代码

但是 ,如许 做的装逼指数依然不够高,你总不能每个类都来这一招吧,固然 不怎么辛劳 ,但每个类都得去写一个构造函数,不利落。

于是,init 访问器用得上了,咱们把 Dog 类改改。

  1. public class Dog
  2. {
  3. public int No { get; init; }
  4. public string Name { get; init; }
  5. public int Age { get; init; }
  6. }
复制代码

你不用再去写带参数的构造函数了,实例化时直接为属性赋值。

  1. Dog x = new Dog
  2. {
  3. No = 100,
  4. Name = "吉吉",
  5. Age = 4
  6. };
复制代码

如许 一来,这些只读属性都有默认的初始值了。

当然,这个赋值只在初始化过程中有效 ,初始化之后你再想改属性的值,没门!

  1. x.Name = "冬冬"; //错误
  2. x.Age = 10; //错误
复制代码

以上就是C#的record 范例 、模式匹配、init 属性详情的详细 内容,更多关于C#的record 范例 、模式匹配、init 属性的资料请关注脚本之家别的 相干 文章!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

avatar 梦的衣裳323 | 2021-9-15 09:06:25 | 显示全部楼层
信admin楼主,考试不挂科!
回复

使用道具 举报

avatar 风残殒落殒d | 2021-9-15 20:27:43 | 显示全部楼层
admin楼主是我最崇拜的人!
回复

使用道具 举报

avatar 涨吧涨吧章 | 2021-9-20 21:16:15 | 显示全部楼层
admin楼主,我告诉你一个你不知道的的秘密,有一个牛逼的网站,他卖的服务器是永久的,我们的网站用 服务器都是在这家买的,你可以去试试。访问地址:http://fwq.mxswl.com
回复

使用道具 举报

avatar 执着等待等wc | 2021-9-21 14:22:00 | 显示全部楼层
好无聊啊!
回复

使用道具 举报

avatar 永远爱你冰塘 | 2021-10-1 22:14:49 | 显示全部楼层
好帖子!
回复

使用道具 举报

avatar 123456911 | 2021-10-5 07:04:16 | 显示全部楼层
投admin楼主一票,不用谢哦!
回复

使用道具 举报

avatar 123457281 | 2021-10-6 10:23:10 | 显示全部楼层
帖子好乱!
回复

使用道具 举报

avatar 珍惜637 | 2021-10-7 05:45:03 | 显示全部楼层
看了这么多帖子,第一次看到这么经典的!
回复

使用道具 举报

avatar 玲嘉婕嘉n | 2021-10-7 20:31:25 | 显示全部楼层
论坛的人气不行了!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则