C# 中的 is 真的是越来越强大越来越语义化(推荐)

一:背景

1. 讲故事

最近发现 C#7 之后的 is 是越来越看不懂了,乍一看花里胡哨的,不过当我静下心来仔细研读,发现这 is 是越来越短小精悍,而且还特别语义化,那怎是一个爽字了得😄,这一篇就和大家简单聊一聊。

二:C#7 之前的 is 如何使用

1. 类型兼容性检测

相信学过 C# 的朋友都会知道 is 是干嘛的,而且还经常和 as 一起比较,前者一般做兼容性检测,后者一般做兼容性转换,这里我就举个例子吧:

 static void Main(string[] args)
  {
   object slot = new Slot() { ClothesName = "上衣" };

   if (slot is Slot)
   {
    Console.WriteLine($"slot is {nameof(Slot)}");
   }

   if (slot is IComparable)
   {
    Console.WriteLine($"slot is {nameof(IComparable)}");
   }
  }

  public class Slot : IComparable
  {
   public string ClothesName { get; set; }

   public int CompareTo(object obj) {return 0;}
  }

从这个例子可以看到, object 类型的 slot 和 Slot, IComparable 都是类型兼容的,非常简单。

2. 遗憾的地方

然而在实际编码中,我相信有很多朋友都会在后续的过程中用到 slot 实例,而上面的这个例子,即使我用 is 检测到了是 Slot 类型,最后我还是要 将 object slot 强转成 Slot类型,做了一次检测,又做了一个强转,这就很奇葩了,如下代码:

 if (slot is Slot)
   {
    var query = (Slot)slot;
    Console.WriteLine($"slot is {nameof(Slot)}, ClothesName={query.ClothesName}");
   }

除非有毛病才写这样的代码,干嘛不直接用 as 尝试性转换将两步合为一步走呢? 修改代码如下:

 var query = slot as Slot;

   if (query != null)
   {
    Console.WriteLine($"slot is {nameof(Slot)}, ClothesName={query.ClothesName}");
   }

这就导致很多场景下,is 都被 as 替代了,搞的 is 成了一个空架子,如果 is 能合并 as 的功能,那就🐂👃了,我觉得这个急需增强。

三:C#7 之后的 is 如何使用

也终于在 C#7 之后对 is 进行了翻天覆地的语法糖改造,导致你初看已经不明白啦😄😄😄,下面我就一一举例来说明吧。

1. is 和 复杂类型/简单类型 的结合

现在就来看一下怎么用新is 解决刚才两次转换的问题,如下代码:

 object slot = new Slot() { ClothesName = "上衣" };

   if(slot is Slot query)
   {
    Console.WriteLine($"slot is {nameof(Slot)}, ClothesName={query.ClothesName}");
   }

这段代码表面意思是:先用 is 检测 slot 是否为 Slot 类型,如果是就赋值给 Slot 类型的 query 变量,哈哈,有点意思吧,为了验证是否如我所说,用反编译工具看看。

ILSpy 反编译

DnSpy 反编译

可以看到,在实操中,编译器都用 as 进行了还原,不过从代码流畅性来看,ILSpy更🐂👃一点。

除了和类实例比较之外,还可以和 int,string,tuple ...进行比较, 代码如下:

 object e = 150;

   //字符串比较
   if (e is "hello") { }

   //整形比较
   if (e is 10) { }

   //tuple 比较
   if (e is (10, 20)) { }

2. is 和 null 的结合

大家在写 sql 的时候判断某一个字段是否为 null,通常都会这样写: username is null 或者 username is not null ,哈哈,这种写法也被引入到 C# 中了,有意思吧,上代码:

 object e = 150;

   if (e is null)
   {
    Console.WriteLine("e is null");
   }

   if (e is not null)
   {
    Console.WriteLine("e is not null");
   }

这么语义化的写法在C#中看到是不是有点不习惯,那为啥在 sql 中就习以为常呢? 其实反编译过来也没啥,就是一个 == 判断,如下代码:

3. is 和 and ,or 的结合

现在大家都看到了 is 通常是放在 if 语句中,既然在 if 语句中,那肯定有很多的逻辑判断,这就需要结合 and,or 构建非常复杂的逻辑关系,不要眼花哦。

object e = 150;

   if (e is >= 100 and <= 200)
   {
    Console.WriteLine($"e={e} 果然 大于 100 并且 小于 200");
   }

   if (e is 100 or 150 or 200)
   {
    Console.WriteLine($"e={e} 是在 100,150,200 三个数字中");
   }

   if (e is not null and not "")
   {
    Console.WriteLine($"e={e},模拟 !string.IsNullOrEmpty 功能");
   }

可以看到最后的: e is not null and not "" 其实等价于 !string.IsNullOrEmpty, 是不是有点意思哈。

这里有一点要提醒的是,上面的 e 在编译器层面都是 object 类型,如果你想在 编译器层面使用 int 运作,还是用 例子1 的方式转换一下哈,如下图所示:

4. is 和 var 的结合

当 is 和 var 结合起来就更🐂👃了,可以实现在 if 判断的过程中生成临时变量,如下代码:

 int e = 150;

   if (e is var i && i >= 100 && i <= 200)
   {
    Console.WriteLine($"e={i} 果然 大于 100 并且 小于 200");
   }

上面代码中的 i 就是一个临时变量,后面做的一切业务逻辑都是基于 i 这个临时变量的,如果还没有领会到精粹,没关系,我举一个项目中的例子吧。。。

我们公司是搞衣物洗涤自动化,也需要对线下 传输线上的衣服进行自动化上挂,取走和衣物组合搭配,举个例子:找到 刚好挂了一件裤子L && 一件上衣L && 总衣服个数=2 的 挂孔号,要是还没听懂就算了,直接上代码说话。

class Program
 {
  static void Main(string[] args)
  {
   var slotList = new List<Slot>()
   {
    new Slot() {SlotID=1, ClothesID=10,ClothesName="上衣", SizeName= "L" },
    new Slot() {SlotID=1, ClothesID=20,ClothesName="裤子", SizeName= "M" },
    new Slot() {SlotID=1, ClothesID=11,ClothesName="皮带", SizeName= "X" },
    new Slot() {SlotID=2, ClothesID=30,ClothesName="上衣", SizeName= "L" },
    new Slot() {SlotID=2, ClothesID=40,ClothesName="裤子", SizeName= "L" }
   };

   //找到 刚好挂了一件裤子L & 一件上衣L & 总衣服个数=2 的 挂孔号
   var query = slotList.GroupBy(m => m.SlotID).Where(m =>
                  m.Where(n => n.SizeName == "L").ToList() is var clothesList &&
                  clothesList.Count(k => k.ClothesName == "裤子") is 1 &&
                  clothesList.Count(k => k.ClothesName == "上衣") is 1 &&
                  m.Key == 2
                )
             .ToDictionary(k => k.Key, v => v.ToList());
  }

  public class Slot
  {
   public int SlotID { get; set; }

   public int ClothesID { get; set; }

   public string ClothesName { get; set; }

   public string SizeName { get; set; }
  }
 }

重点在于上面代码的 m.Where(n => n.SizeName == "L").ToList() is var clothesList ,这里的 clothesList 就是临时变量,它存放了所有 尺寸L 的衣物,后续的检索都是基于这个 clothesList,是不是大大提高了检索速度~~~

四:总结

我觉得 is 的功能增强早就该出现了,现在终于搞定了,越来越人性化,键盘敲击次数越来越少,头发也不落了,甚至又开始第二春了,总的来说还是那句话,C# 大法🐂👃。

更多高质量干货:参见我的 GitHub: dotnetfly

到此这篇关于C# 中的 is 真的是越来越强大越来越语义化的文章就介绍到这了,更多相关C# 中 is 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C# Distinct和重写IEqualityComparer时要知道的二三事

    我们在想对一个可枚举的对象集合进行去重操作时,一般第一个想到的就是就是Linq的Distinct方法. 先定义一个类,然后使用Distinct方法去重 class Man { public int Age { get; set; } public string Name { get; set; } public string Adress { get; set; } public decimal Weight { get; set; } public decimal Height { get;

  • C# List引用类型克隆的3种方法

    前言 有时候我们想克隆一个List去做别的事,而不影响原来的List,我们直接在list后面加上小点点,发现并没有Clone这样的扩展函数.这时候就只有自己扩展了. 尝试了三种方式,测试都通过了,至于性能方面我还没有做测试. 下面话不多说了,来一起看看详细的介绍吧 一.反射 public static List<T> Clone<T>(this List<T> list) where T : new() { List<T> items = new List&

  • C# 中的 is 真的是越来越强大越来越语义化(推荐)

    一:背景 1. 讲故事 最近发现 C#7 之后的 is 是越来越看不懂了,乍一看花里胡哨的,不过当我静下心来仔细研读,发现这 is 是越来越短小精悍,而且还特别语义化,那怎是一个爽字了得

  • 详解IDEA 中使用Maven创建项目常见错误和使用技巧(推荐)

    使用idea的运行程序时,出现jar包不存在的错误(pom.xml文件中有依赖,而且代码没有红色的). 解决方法:Maven安装目录下的conf文件下的setting.xml文件中不要加入本地仓库路径设置,直接在idea中设置. tomcat启动maven项目出现jar包不存在的错误.解决方法:在pom.xml文件中加上war maven依赖下载速度太慢.解决方法:在maven安装目录下的conf文件下的setting.xml中,设置阿里云的镜像仓库地址. <mirror> <id>

  • 详解JavaScript中if语句优化和部分语法糖小技巧推荐

    目录 前言 if else 基本使用 简化if判断和优化代码 单行if else 使用&& || 优化 使用三目运算符优化 合并if 使用includes 或者indexof 使用switch流程 优化 多个if else 使用对象 key-value 优化多条if语句 使用map 推荐一些常用的JavaScript语法糖 箭头函数 三目运算符处理函数 函数默认参数处理 数据类型转换 Null.Undefined 布尔值等特殊值处理,使用||结合! 链判断运算符 链判断运算符 空值合并操作

  • C#中Try-Catch语句真的影响程序性能吗?

    很多帖子都分析过Try-Catch的机制,以及其对性能的影响. 但是并没有证据证明,Try-Catch过于损耗了系统的性能,尤其是在托管环境下.记得园子里有位网友使用StopWatch分析过Try-Catch在不同情况下,与无Try-Catch的代码相比,代码运行的时间指标,结果并没有很大差异. 下面我来结合IL分析一下Try-Catch吧. ● 机制分析 .Net 中基本的异常捕获与处理机制是由try-catch-finally块来完成的,它们分别完成了异常的监测.捕获与处理工作.一个try块

  • 关于golang中map使用的几点注意事项总结(强烈推荐!)

    目录 前言 1 使用 map 记得初始化 2 map 的遍历是无序的 3 map 也可以是二维的 4 获取 map 的 key 最好使用这种方式 5 map 是并发不安全的 ,sync.Map 才是安全的 总结 前言 日常的开发工作中,map 这个数据结构相信大家并不陌生,在 golang 里面,当然也有 map 这种类型 关于 map 的使用,还是有蛮多注意事项的,如果不清楚,这些事项,关键时候可能会踩坑,我们一起来演练一下吧 1 使用 map 记得初始化 写一个 demo 定义一个 map[

  • Java中实现文件上传下载的三种解决方案(推荐)

    java文件上传与文件下载是程序开发中比较常见的功能,下面通过本文给大家介绍Java中实现文件上传下载的三种解决方案,具体详情如下所示: 第一点:Java代码实现文件上传 FormFile file=manform.getFile(); String newfileName = null; String newpathname=null; String fileAddre="/numUp"; try { InputStream stream = file.getInputStream(

  • python3中os.path模块下常用的用法总结【推荐】

    abspath 返回一个目录的绝对路径 Return an absolute path. >>> os.path.abspath("/etc/sysconfig/selinux") '/etc/sysconfig/selinux' >>> os.getcwd() '/root' >>> os.path.abspath("python_modu") '/root/python_modu' basename 返回一个

  • MySQL中使用group by 是总是出现1055的错误(推荐)

    因为在MySQL中使用group by 是总是出现1055的错误,这就导致了必须去查看是什么原因了,查询了相关的资料,现在将笔记记录下来,以便后面可以参考使用: sql_mode:简而言之就是:它定义了你MySQL应该支持的sql语法,对数据的校验等等 select @@sql_mode:使用该命令我们可以查看我们当前数据库的sql_mode mysql> select @@sql_mode; +--------------------------------------------------

  • Java中数组的使用与注意事项详解(推荐)

    目录 一.初始数组 二.数组的创建 三.使用数组时的注意事项 (1)初始化问题 (2)数组长度的使用 (3)有关数组长度的问题 (4)对于数组的访问 (5)数组的遍历 三.数组的类型 1.每个部分数据区的概念: 2.数组在JVM当中的使用情况 3.引用类型的注意事项 四.关于引用类型的返回值 总结 一.初始数组 数组的概念:数组就是一个用来存储相同类型数据的一个容器. 为什么要使用数组? 当我们要存储大量相同类型的时候,通过配合循环来使用就会大量减少代码复杂程度 数组的特点: (1)数组是一种引

  • 自己收集比较强大的分页存储过程 推荐

    (下面的代码原来我想用折叠的代码的,但是在google里面老是添加不了折叠的代码,所以就整屏的贴出来了,望大家不要见外.) 朋友的比较好的存储过程.优点是:性能非常的高,每次查询都是根据ID查询,每次都是对一半的数据进行分页.缺点是:当有多个排序条件时,分页数据显示会出现问题.(该问题在第二个网友的分页存储过程中有解决的方法). 复制代码 代码如下: set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER PROCEDURE [dbo].[proc

随机推荐