如何在C#可空性分析中告知编译器结构体非空字段可能为null?
解决方案
以下几种方案均不需要修改原结构体Str字段的非可空声明,可实现让编译器识别出实例字段可能为空的效果:
方案1:自定义扩展方法返回可为空值类型
针对值类型的FirstOrDefault返回默认初始化实例的问题,可以写扩展方法返回Nullable<T>,找不到匹配项时直接返回null,强制编译器要求你做非空校验:
using System.Collections.Generic; using System.Linq; public static class StructEnumerableExtensions { // 针对结构体类型的FirstOrNull扩展 public static T? FirstOrNull<T>(this IEnumerable<T> source, Func<T, bool> predicate) where T : struct { foreach (var item in source) { if (predicate(item)) return item; } return null; } }
使用方式:
MyStruct? found = list.FirstOrNull(item => item.Str == "B"); // 编译器会强制你判断是否有值,未校验直接访问Value会触发警告 if (found.HasValue) { Console.WriteLine(found.Value.Str.Length); }
方案2:用MemberNotNullWhen属性标注结构体校验方法
在原有结构体中添加校验方法,通过特性告知编译器校验通过后字段的可空状态,同时可以避免静态分析工具的误提示:
using System.Diagnostics.CodeAnalysis; struct MyStruct { public readonly string Str; public MyStruct(string str) { Str = str; } // 标记当返回值为true时,Str字段一定不为空 [MemberNotNullWhen(true, nameof(Str))] public bool IsValid() => Str != null; }
使用方式:
MyStruct found = list.FirstOrDefault(item => item.Str == "B"); if (found.IsValid()) { // 编译器已确认Str不为空,不会触发警告 Console.WriteLine(found.Str.Length); }
方案3:临时强制转换为可空类型
如果不想修改原有代码结构,仅需要在局部处理单个实例的可空性,可以手动将字段强转为可空引用类型,覆盖编译器的默认可空判断:
MyStruct found = list.FirstOrDefault(item => item.Str == "B"); // 强转为可空字符串,编译器会识别该值可能为空 string? str = (string?)found.Str; if (str != null) { Console.WriteLine(str.Length); }
补充说明
你提到的类似!反向操作的语法(标记非可空值实际可能为空)目前C#官方还没有支持,现有场景下使用上述三种方案即可覆盖绝大多数需求。
内容的提问来源于stack exchange,提问作者Walt D
相关产品推荐
相关产品推荐

