如何解决关于 DisallowNull 的 CS8607 警告?

How to address CS8607 warning about DisallowNull?

在 .NET 5 class 库中考虑此 C# class,并启用 nullable reference types 功能

public class ContraMapComparer<T, T1> : IEqualityComparer<T1>
{
    private readonly IEqualityComparer<T> source;
    private readonly Func<T1, T> selector;

    public ContraMapComparer(IEqualityComparer<T> source, Func<T1, T> selector)
    {
        this.source = source;
        this.selector = selector;
    }

    public bool Equals(T1? x, T1? y)
    {
        if (x is null && y is null)
            return true;
        if (x is null || y is null)
            return false;

        return source.Equals(selector(x), selector(y));
    }

    public int GetHashCode([DisallowNull] T1 obj)
    {
        return source.GetHashCode(selector(obj));
    }
}

[DisallowNull] 属性由 Visual Studio 的 启用界面 快速操作添加。

编译时,编译器发出此警告:

CS8607    A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]

显然,如果您启用了将警告视为错误(我有),这意味着代码无法编译。

如何解决这个问题?

我试过向 objsourceselector 添加 运行 次空守卫,但这没有帮助。我也尝试将 [DisallowNull] 属性添加到 sourceselector,但这也没有帮助。

[DisallowNull] 阅读 the documentation 让我 none 变得更聪明。

即使删除 [DisallowNull] 属性也无法解决问题。编译器警告仍然存在。

我能够识别的唯一修复是 #pragma 来抑制警告:

#pragma warning disable CS8607 // A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]
                return source.GetHashCode(selector(obj));
#pragma warning restore CS8607 // A possible null value may not be used for a type marked with [NotNull] or [DisallowNull]

还有其他修复方法吗?

Func<T1,T> 未注释为不是 return null。引入一个支持该功能的新代表:

[return:NotNull]
public delegate T NonNullFunc<in T1, out T>(T1 value);
public class ContraMapComparer<T, T1> : IEqualityComparer<T1>
{
    private readonly IEqualityComparer<T> source;
    private readonly NonNullFunc<T1, T> selector;

    public ContraMapComparer(IEqualityComparer<T> source, NonNullFunc<T1, T> selector)
    {
    //As before

这比允许空值或使用 pragma 更好,因为它应该强制使用任何表达式来定义 selector,它不会 return null.

(您可能还希望对委托的输入参数进行注释以禁止空值)

警告不是在谈论 [DisallowNull] 方法参数的 [DisallowNull] 属性。它正在谈论 source.GetHashCode 调用!毕竟这个调用也是在调用IEqualityComparer.GetHashCode,它有[DisallowNull]属性

selector(obj) returns a T,但是 T 对它没有限制,所以它可以是可空类型,如 string?int?。如果它是可空类型,则它可以为空。但是 source.GetHashCode 不允许空值!因此警告。

I've tried adding run-time null guards to obj, source, and selector

您应该检查 selector(obj),而不是 sourceselectorobjselector(obj)是可以为null的东西,这里不允许为null。

T t = selector(obj);
if (t == null) {
    throw new ArgumentException("obj maps to a null!", nameof(obj));
}
return source.GetHashCode(t);

虽然我很欣赏前面两个解释问题的答案,但我发现 none 的建议解决方案是最佳的。

幸运的是,Jeroen Mostert 在评论中提出了一个更好的解决方案:Constrain T to be notnull:

public class ContraMapComparer<T, T1> : IEqualityComparer<T1> where T : notnull

我就是这么做的,解决了这个问题。