C#存在运算符重载的类如何安全执行null空值检查
问题背景
基于.NET Framework v4.5.2开发的应用执行如下代码时,会抛出NullReferenceException异常:
if (CurrentZip.Container.Exists)
需要为该逻辑增加判空校验,确保CurrentZip.Container不为null后再访问Exists属性。但Container的类型为第三方实现的RichFileInfo,该类型实现了相等运算符重载,且重载逻辑未对入参做null校验,直接访问实例的FullName属性,重载代码如下:
public static bool operator ==(RichFileInfo x, RichFileInfo y) { return String.Equals(x.FullName, y.FullName, StringComparison.OrdinalIgnoreCase); } public static bool operator !=(RichFileInfo x, RichFileInfo y) { return !String.Equals(x.FullName, y.FullName, StringComparison.OrdinalIgnoreCase); }
该缺陷重载导致直接执行CurrentZip.Container != null的判空逻辑时,同样会抛出NullReferenceException,需要找到存在自定义运算符重载的场景下安全完成null检查的方案。
可用解决方案
所有方案的核心逻辑都是绕过RichFileInfo自定义的有缺陷的相等运算符,走最基础的引用相等判断:
- 使用
object.ReferenceEquals()静态方法判空
该方法是System.Object定义的静态方法,直接判断两个参数是否指向同一块内存引用,不会触发任何自定义的运算符重载,是兼容性最好、最稳妥的判空方式,适用于所有.NET版本,示例代码:if (!ReferenceEquals(CurrentZip.Container, null)) { // 此时Container确定不为null,可以安全访问成员 if (CurrentZip.Container.Exists) { // 执行业务逻辑 } } - 转成
object类型后再做相等判断
自定义的相等运算符只会在两个操作数至少有一个匹配RichFileInfo类型时触发,将待判断的值先转为object类型后,比较操作会走object的默认引用相等逻辑,不会触发有缺陷的重载,示例代码:object containerRef = CurrentZip.Container; if (containerRef != null) { if (CurrentZip.Container.Exists) { // 执行业务逻辑 } } - 使用
is模式匹配判空
C# 7及以上版本支持的is null/is object判断是编译器层面做的引用检查,不会调用用户自定义的相等运算符,写法更简洁。注意.NET Framework 4.5.2默认搭配的C# 5编译器不支持该语法,如果你使用高版本Visual Studio编译、开启了高版本C#语言支持,可以使用该写法,示例代码:if (!(CurrentZip.Container is null)) // 等价写法:if (CurrentZip.Container is object) { if (CurrentZip.Container.Exists) { // 执行业务逻辑 } }
注意事项
禁止直接对RichFileInfo类型的变量使用== null或!= null做判断,只要比较操作的任意一侧是RichFileInfo类型,就会触发存在缺陷的运算符重载,直接抛出空引用异常。
内容的提问来源于stack exchange,提问作者Black
相关产品推荐
相关产品推荐

