C#中如何为GetOrNew的Func参数配置NotNullIfNotNull规则
解决方案
针对你提到的委托参数可空性关联的需求,有两种常用实现方式:
方案1:.NET 7+ 直接使用特性标注
.NET 7 扩展了[NotNullIfNotNull]特性的适用范围,支持直接标注委托类型的参数,明确关联GetOrNew的key参数和factory委托的入参的可空性:
using System.Diagnostics.CodeAnalysis; public class X { public T GetOrNew<T, TKey>(TKey? key, [NotNullIfNotNull(nameof(key))] Func<TKey?, T> factory){ // 原有代码逻辑完全不变 var instance = factory(key); return instance; } }
该标注会告诉编译器规则:当传入GetOrNew的key不为null时,factory的入参也一定不为null。你的两种调用场景都能完美适配:
- 传入非空
key时,编译器会自动判定factory的入参非空,调用index.GetRandomPerson()不会触发警告 - 传入null作为
key时,factory的入参仍判定为可空,符合你的兼容要求
方案2:重载方案(兼容.NET 6及更早版本)
如果你的项目需要兼容更低版本的.NET运行时,可以通过方法重载实现同样的效果,不需要修改原有核心逻辑:
public class X { // 非空key的重载,供key不为null的场景调用 public T GetOrNew<T, TKey>(TKey key, Func<TKey, T> factory) where TKey : notnull { // 内部复用可空版本的实现,用!抑制非空警告(逻辑上已经保证key非空) return GetOrNew(key, k => factory(k!)); } // 原有可空key的重载,供key可能为null的场景调用 public T GetOrNew<T, TKey>(TKey? key, Func<TKey?, T> factory){ // 原有代码逻辑完全不变 var instance = factory(key); return instance; } }
编译器会根据你传入的key的可空性自动匹配对应重载:
- 传入非空
key时匹配第一个重载,factory的入参直接声明为非空,无警告 - 传入null作为
key时匹配第二个重载,factory的入参为可空类型,符合使用需求
两种方案都不需要修改你现有的调用代码,也完全保留了GetOrNew支持传入null作为合法参数的能力。
内容的提问来源于stack exchange,提问作者RedX
相关产品推荐
相关产品推荐

