dotnet 警惕 C# 的 is var 写法
本文将和大家介绍 C# 语言设计里面,我认为比较坑的一个语法。通过 is var 的写法,会让开发者误以为 null 是不被包含的,然而事实是在这里的 var 是被赋予含义的,将被允许 null 通过判断逻辑,于是就会让开发者收到了奇怪的空异常
比如看看以下的代码,大家猜猜控制台是否会输出
IFoo? foo = null;
if (foo is var f2)
{
Console.WriteLine($"居然进来了。 F2={f2}");
}
答案是控制台居然输出居然进来了,也就是说 null 在 is 判断里面是通过,而 var 的含义似乎不只是一个语法上的可有可无的关键词而已,而是赋予了运行时含义的关键词
换句话说就是在以上代码里面的 var 关键词已经违背了 C# 初始设计 var 里面的含义了。最初的 C# 里面的 var 只是一个在构建过程中可以被平替为具体类型的关键词,是一个不会影响到语义、运行时逻辑的语法而已。然而在 is 这里面,将 var 当成了一个可以处理空值的特殊语法结构
这和咱长久的使用 is 来过滤空值的编程思想是冲突的,我感觉绝大部分开发者在写到 is var 的过程,将会想着应该是自动过滤掉 null 值。然而事实是按照 C# 的新设计(C# 7.0-8.0)来说,这里的 var 是一个模式匹配的语法而已,且 var 不再只是一个可有可无的关键词,而是将会影响运行逻辑的关键词
相信许多开发者会和我一样,第一次编写 is var 的时候,会认为一定会过滤掉空值,导致出现了预期之外的空异常
通过以上的代码测试,可以看到以上代码里面的 var 和 IFoo 是不等价的。咱更进一步编写更多的代码,用来测试一下具体的语法行为,如以下代码的两个 var 的含义是完全不同的
IFoo? foo = null;
var f1 = foo;
if (foo is var f2)
{
Console.WriteLine($"居然进来了。 F2={f2}");
}
第一个 var 是传统的用法,只是让开发者省略编写重复的代码,没有影响到任何的语义和运行逻辑。第一个 var 和 IFoo 是等价的
然而第二个 var 在上面代码里面,却不能够平替为 IFoo 类型,试试看替换为 IFoo 类型试试,如以下代码,大家可以看到运行逻辑是完全不相同的
var f1 = foo;
if (foo is var f2)
{
Console.WriteLine($"居然进来了。 F2={f2}");
}
if (foo is IFoo f3)
{
Console.WriteLine($"不进来");
}
如果将 is var 替换为 is IFoo 则非常符合预期的过滤掉 null 值
这个如此奇怪的行为是如何被设计出来的,设计这样的行为为什么能够通过大家的语法评审?难道有这么多的开发者大佬脑袋都被大门夹了?
整个 C# 语言的设计是在不断迭代的,现在已经是 C# 12 了。在当年 C# 7.0 时候引入了 pattern 写法时,大家都为此开森,因为这个语法写起来特别漂亮。然而潜藏的 is var 就在 8.0 的对 pattern 模式匹配里面的更进一步改进里面,不得不被引入了这个奇怪的行为,看看以下咱平时写的很爽的语法
static Point Transform(Point point) => point switch
{
var (x, y) when x < y => new Point(-x, y),
var (x, y) when x > y => new Point(x, -y),
var (x, y) => new Point(x, y),
};
以上的模式匹配里面其实就隐含了 is var 的定义设计,准确来说 is 和 switch 都属于 C# 语法里面的模式匹配的语法,两者应该都有相同的设计
更何况在过滤空对象时,还可以使用 is {}
语法,这就导致了如果将 is var 设计为过滤 null 对象,将会和 is {}
语法是重叠的,浪费关键词。为了能够更好的实现比较长的链路短写法,于是就如官方文档所述将 var 匹配当成为对一切的匹配,包含 null 对象的匹配
换句话说使用 var 匹配就相当于只是拿出来一个变量而已,而不会做其他任何的处理逻辑。用途之处在于大概如下的代码里面
static bool IsFoo() =>
GetFxx() is var fxx
&& CheckXx(fxx) is var result
&& DoXxx(result);
以上代码可以非常方便的利用短路逻辑和 is var 逻辑取出变量执行后续过程。如此写法的完全展开形式也是非常长的
static bool IsFoo()
{
if (GetFxx() is var fxx)
{
if (CheckXx(fxx) is var result)
{
return DoXxx(result);
}
}
return false;
}
如此可以看来 is var 的设计还是在一些逻辑上可以很好的减少代码量的
这个 is var 的决议最早的有记录的会议可以追溯到 2015 那会,详细请看 https://github.com/dotnet/csharplang/blob/20dde78e36028ac0492035f51e28437a92d1b4f2/meetings/2015/LDM-2015-01-21.md 和 https://github.com/dotnet/csharplang/blob/20dde78e36028ac0492035f51e28437a92d1b4f2/meetings/2015/LDM-2015-03-10-17.md 等会议记录内容
从 IL 层面上看 is var 的语法,可以发现 is var 只是就是一个局部变量赋值,从 IL 上看的 is 判断只是空气而已,什么都没有
如以下的 C# 代码和 IL 的对应,可以看到 if (foo is var f2)
和 var f2 = foo;
是等价的
C#:
if (foo is var f2)
IL:
IL_0005: ldloc.0 // foo
IL_0006: stloc.2 // f2
-------------------------------------
C#:
var f2 = foo;
IL:
IL_0007: ldloc.0 // foo
IL_0008: stloc.1 // f2
这和 if (foo is IFoo f3)
的逻辑是完全不一样的,如以下的 C# 和 IL 对应代码
C#:
if (foo is IFoo f3)
IL:
IL_0007: ldloc.0 // foo
IL_0038: isinst IFoo
IL_003d: stloc.1 // f3
IL_003e: ldloc.1 // f3
IL_003f: brfalse.s IL_006a
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 2ec91207fff919837fff1c3121d57d0172b4f2bb
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 2ec91207fff919837fff1c3121d57d0172b4f2bb
获取代码之后,进入 FaydeenereqelnairderlaHuwicagall 文件夹
dotnet 警惕 C# 的 is var 写法的更多相关文章
- Cookies 初识 Dotnetspider EF 6.x、EF Core实现dynamic动态查询和EF Core注入多个上下文实例池你知道有什么问题? EntityFramework Core 运行dotnet ef命令迁移背后本质是什么?(EF Core迁移原理)
Cookies 1.创建HttpCookies Cookie=new HttpCookies("CookieName");2.添加内容Cookie.Values.Add(&qu ...
- EntityFramework Core 运行dotnet ef命令迁移背后本质是什么?(EF Core迁移原理)
前言 终于踏出第一步探索EF Core原理和本质,过程虽然比较漫长且枯燥乏味还得反复论证,其中滋味自知,EF Core的强大想必不用我再过多废话,有时候我们是否思考过背后到底做了些什么,到底怎么实现的 ...
- WPF 使用 Silk.NET 进行 DirectX 渲染入门
本文告诉大家如何使用 dotnet 基金会新开源的 Silk.NET 库调用 DirectX 进行渲染的方法.此库是对 DirectX 的底层基础封装,用上了 dotnet 和 C# 的各个新特性,相 ...
- 前端编码规范之JavaScript
上次浅谈了下关于CSS的编码规范,大部分童鞋持赞同意见,仍存在一些童鞋不太理解这些规范的意义. 如果是个人或者小作坊开发,其实这些所谓的编码规范也没啥意思,因为大家写好的代码直接就给扔到网上去了,很少 ...
- 今天第一次接触到typescript,看了第一个知识点就是变量的声明,来回忆回忆,做做笔记
以前只用过JavaScript原生写网站特效,今天还是第一次听说typescript的,然后看了一下它的基本知识,感觉很像Java,真的太像了,但是又有不同点.很让我惊奇看到的第一个知识点就和以前不同 ...
- ES6特性
一.ES6特性: let, const, class, extends, super, arrow functions, template string, destructuring, default ...
- ASP.NET Core 网站发布到Linux服务器
长期以来,使用.NET开发的应用只能运行在Windows平台上面,而目前国内蓬勃发展的互联网公司由于成本的考虑,大量使用免费的Linux平台,这就使得.NET空有一身绝技但无法得到广大的施展空间,.N ...
- ASP.NET Core 网站发布到Linux服务器(转)
出处;ASP.NET Core 网站发布到Linux服务器 长期以来,使用.NET开发的应用只能运行在Windows平台上面,而目前国内蓬勃发展的互联网公司由于成本的考虑,大量使用免费的Linux平台 ...
- NET Core 跨平台执行命令、脚本
一.前言 我们可能会遇到需要在程序中执行一些系统命令,来获取一些信息:或者调用shell脚本..NET Core 目前已经可以跨平台执行,那么它如何跨平台执行命令呢,请看下面的讲解. 二.Proces ...
- FreeSql 过滤器使用介绍
FreeSql.Repository 实现了过滤器,它不仅是查询时过滤,连删除/修改/插入时都会进行验证,避免数据安全问题. 过滤器 目前过滤器依附在仓储层实现,每个仓储实例都有 IDataFilte ...
随机推荐
- View事件机制源码分析
目录介绍 01.Android中事件分发顺序 02.Activity的事件分发机制 2.1 源码分析 2.2 点击事件调用顺序 2.3 得出结论 03.ViewGroup事件的分发机制 3.1 看一下 ...
- 记录--P0事故预警
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 背景 某一天,前端小余同学和后端别问我小哥在做登录业务接口对接,出于业务的特殊性和安全性的考虑,她和后端小哥约定"user&qu ...
- Excel多列求平均值
数据源如下所示 需求描述:现在需要根据水果名称和月份求出对应水果的平均单价 一.添加一列辅助列(=A2&B2) 二.Ctrl+A选择所有数据插入数据透视表,选择辅助列到行,客单价到值(值字段设 ...
- 超详细的彻底卸载VMware虚拟机方法
一.在卸载VMware虚拟机之前,要先把与VMware相关的服务和进程终止 1.在windows中按下[Windows键],搜索[服务]设置,然后打开: 2.找到以VM打头命名的服务,然后右键停止这些 ...
- 脚本推荐-verilog自动对齐
verilog自动对齐脚本 简介 vscode中的verilog-utils可以自动例化 但是没有保留注释 导致注释丢失比较严重 这个为后期的维护带来了巨大的工作量 基于此,使用TCL脚本完成同样的工 ...
- KingbaseES V8R6 运维案例 --ksql访问动态库问题
KingbaseES V8R6数据库运维案例之---ksql访问动态库问题 案例说明: CentOS环境下,在安装和初始化数据库实例后,启动数据库服务,通过ksql连接访问时出现以下故障: 经检查,是 ...
- JDBC访问KingbaseES数据库异常 -- 案例分析
应用使用jdbc访问KingbaseES数据库发生异常:SocketTimeoutException Read timed out 一.异常现象: 应用显示ERROR信息: Caused By: ja ...
- C++ 中的 volatile 和 atomic
C++ 中的 volatile 和 atomic 0. TL;DR std::atomic 用于多线程并发场景,有两个典型使用场景: 原子操作:对 atomic 变量的操作(读/写/自增/自减)仿佛受 ...
- MVC架构设计浅析(WEB网页开发)
MVC架构设计浅析 杨传伟 (石家庄铁道大学信息科学与技术学院,河北省,石家庄市,050043) 摘 要:本文以图书管理系统为案例(当前主流框架SpringMVC的原理来分析MVC的设计理念等),深入 ...
- ASCII编码的全面介绍
1. ASCII编码的定义和历史 ASCII(American Standard Code for Information Interchange)是一种用于将文本字符转换为数字编码的标准,最初由美国 ...