如何解决C#中与[DisallowNull]相关的CS8607编译警告问题?
警告根源
该CS8607警告并非来自GetHashCode的入参obj,而是源于selector(obj)的返回值可能为null,而IEqualityComparer<T>.GetHashCode方法的入参本身标记了[DisallowNull]要求非空,编译器无法自动确认selector(obj)的返回值一定非空,因此抛出警告。
更合理的修复方案
方案1:使用空包容运算符
如果业务逻辑可以保证非空的obj传入selector后永远不会返回null,直接在可能为null的返回值后加!空包容运算符即可消除警告,代码改动最小:
public int GetHashCode([DisallowNull] T1 obj) { return source.GetHashCode(selector(obj)!); }
方案2:添加空值校验+显式抛出异常
如果需要兼容selector可能返回null的场景,可以增加运行时空值校验,明确异常逻辑,同时编译器会识别到返回值为空时已经抛出异常,不会走到GetHashCode调用逻辑,也会自动消除警告:
public int GetHashCode([DisallowNull] T1 obj) { var convertedValue = selector(obj); if (convertedValue == null) { throw new InvalidOperationException("Selector cannot return null for non-null input."); } return source.GetHashCode(convertedValue); }
同时建议在构造函数中对入参source和selector添加非空校验,避免后续空引用问题:
public ContraMapComparer(IEqualityComparer<T> source, Func<T1, T> selector) { this.source = source ?? throw new ArgumentNullException(nameof(source)); this.selector = selector ?? throw new ArgumentNullException(nameof(selector)); }
方案3:给泛型参数加非空约束
如果业务场景中T本身就是永远非空的类型,可以直接给泛型参数添加notnull约束,从类型层面消除空值可能性,不需要修改方法内代码:
public class ContraMapComparer<T, T1> : IEqualityComparer<T1> where T : notnull { // 类内其他代码保持原有逻辑即可 }
方案4:标记委托返回值非空
在构造函数的selector参数上添加返回值非空特性,告诉编译器该委托的返回值永远不会为空,后续所有selector调用的返回值都会被识别为非空,警告自动消除:
public ContraMapComparer(IEqualityComparer<T> source, [return:DisallowNull] Func<T1, T> selector) { this.source = source ?? throw new ArgumentNullException(nameof(source)); this.selector = selector ?? throw new ArgumentNullException(nameof(selector)); }
内容的提问来源于stack exchange,提问作者Mark Seemann
相关产品推荐
相关产品推荐

