首页 火币pro官网下载文章正文

七爪源码:C#中使用'is'而不是'=='的Null检查的区别

火币pro官网下载 2022年10月21日 11:02 50 Connor

myObject == null 或 myObject 为 null 有什么区别?

我发现有很多人认为 null 检查是和不是(在 C# 9 中引入)只是相等或不等运算符(== 和 !=)的语法糖。

笔记

在 C# 9 之前,没有任何“不是”支持,要获得相同的结果,您需要执行“!(myObject is null)”更冗长且更难阅读

但实际上,不仅仅是语法糖,我们可以使用 IL 和 C# 的反编译代码来看看幕后发生了什么。

将使用sharplab.io。

SharpLab.io 是一个令人难以置信的工具,因为它为我们提供了一种简单的方法来反编译和检查编译器如何在线转换我们的代码,而无需任何额外的工具或像 Visual Studio 这样的 IDE。

如果您想要一个更完整的 IL 反编译工具以便能够更轻松地导航复杂的项目,我推荐使用 Visual Studio 扩展 ILSpy。

因此,事不宜迟,让我们看一个非常简单的案例,一个“if 子句”来验证对象实例是否为空。

但是等等,我不是说 is 不仅仅是语法糖吗? 除了 dup 指令之外,IL 看起来几乎相同,这对本示例没有任何显着差异。 dup 指令在这里所做的是出于性能原因复制堆栈的顶部元素。

那么is和==实际上有什么区别呢?

好吧,您可能知道(或可能不知道),在 C# 中我们可以覆盖默认的运算符行为。

例如,在上面的那个 Test 类中,我可以做这样的事情。

展开全文

public class Test {

public static bool operator ==(Test x, Test y) => false;

public static bool operator !=(Test x, Test y) => true;

这样,我实际上覆盖了等式和不等式运算符的默认行为。

对于这个例子,完全打乱了这些运算符的操作流程,说 == 将始终返回 false 并且 != 将始终返回 true。

好的,现在我已经覆盖了这些操作员的行为,IL 看起来如何?

好的,现在我们可以开始看到差异了。

在上图中,您可以看到相等运算符实际上会调用覆盖运算符,其中“is”保持不变。

让我们看一下 C# 编译代码以更好地理解为什么会这样。

在这一点上,为什么相等运算符调用被覆盖的运算符而“is”运算符不是,这一点非常明显。

相等调用必须保证您的类签名得到尊重,这就是强制转换为 Test 类的原因并调用我们的相等方法,其中“is”运算符强制转换为普通对象,忽略相等运算符的任何自定义实现。

因为 == 总是返回 false,所以“if (test1 == null)”永远不会为真。

当我们想要保证某些东西不是 null 以避免臭名昭著的 NullReferenceException 时,事情会变得更加危险。

那么现在让我们看看不等式运算符。

结果。

我相信在这一点上很明显这会导致问题,对吧?

如果您要验证一个对象不为 null 以安全地访问它的属性,那么您将到处都有 NullReferences。

在这一点上你可能会质疑但为什么有人会做这样的事情?

嗯,我们非常习惯将各种来源的第三方库、其他公司的包、个人开发人员、NuGet 存储库中的一些随机包等合并到我们的项目中。

也许这些包的某些新版本可能会有意或无意地引入类似这样的错误,很难发现您的代码无法保证对象不为空的确切位置。

所以我应该去改变我所有的空检查来遵循这个模式吗?答案将是古老的陈词滥调“视情况而定”。

您的项目是否有一个或多个第三方库?它们来自可靠的来源?

因此,这里还有一些关于将 null 检查从 == 更改为 is 的提示,以避免大麻烦。

希望这可以帮助您了解在 null 检查中使用“is”或“==”的细微差别。

让我知道你在评论中的想法。

发表评论

火币交易所(huobi) | 火币全球站官网入口 备案号:川ICP备66666666号