如何抑制可能的空引用警告

Posted

技术标签:

【中文标题】如何抑制可能的空引用警告【英文标题】:How to suppress Possible Null Reference warnings 【发布时间】:2020-04-23 09:59:01 【问题描述】:

我正在使用 c# 8 中的可为空类型,但我发现了一个困扰我的问题。 假设我有一个采用可为空参数的方法。当参数为空时,我想抛出一个特定的异常。但我希望该方法干净并在其他地方检查参数。 check 方法抛出异常,所以方法后面的参数不能为空。 不幸的是,编译器没有看到这一点并向我发出警告。 方法如下:

    public void Foo(string? argument)
    
        GuardAgainst.Null(argument, nameof(argument));
        string variable = argument; // <-- Warning CS8600  Converting null literal or possible null value to non - nullable type
        var length = argument.Length; //<--Warning CS8602  Dereference of a possibly null reference
    

检查方法如下:

    public static void Null(string? text, string paramName)
    
        if (text == null)
            throw new ArgumentNullException(paramName);
    

现在,我可以像这样抑制警告:

#pragma warning disable CS8602
var length = argument.Length;
#pragma warning restore CS8602

但这有点扼杀了我保持代码清洁的意图。 所以我的问题是:有没有更好的方法来抑制警告?或者也许告诉编译器从现在开始保证参数不为空?

【问题讨论】:

为什么不使用简单的if .. != null 声明? 你不能让Null 返回一个不可为空的字符串并将其作为分配给variable 的一部分调用吗? 当然,我想过。然后我会有 var variable = GuardAgainst.Null(parameter, nameof(parameter));所以我必须为我拥有的每个参数创建一个变量。这是迄今为止最干净的解决方案,但我想知道是否有更好的选择 This is the cleanest solution so far GuardAgainst 和.Null() 的实现。虽然最终取决于具体情况,但有些人可能会认为这不是很干净,特别是当替代方案是在 if 语句中进行简单的 null 检查时。在这种情况下,clean 对您意味着什么?是什么让clean 的解决方案比任何其他解决方案或多或少? 请试试这个:docs.microsoft.com/de-de/dotnet/fundamentals/code-analysis/… 【参考方案1】:

这就是你想要的:

public static void Null<T>([NotNull] T? value, string paramName)

    if (value == null)
        throw new ArgumentNullException(paramName);

[NotNull] 属性指示分析,调用此方法后,value 将不再是null

这意味着您不需要! 运算符,它更干净、更自然。

void M(string? argument)

    GuardAgainst.Null(argument, nameof(argument));
    string variable = argument; // no warning
    // ...

此处使用不受约束的泛型类型参数T 意味着此方法适用于引用类型(例如string)和可空值类型(例如int?)。

如果您使用的是 .NET 6,则可以通过 CallerArgumentExpressionAttribute 进一步简化此操作,如下所示:

public static void Null<T>(
    [NotNull] T? value,
    [CallerArgumentExpression(parameterName: "value")] string? paramName = null)

    if (value == null)
        throw new ArgumentNullException(paramName);

这样,第二个参数可以省略,调用者可以简化为:

GuardAgainst.Null(argument);

认为类型上的? 说明符意味着两件事:1)在调用之前该值可以为空,2)之后该值可以为空。另一种写法是[AllowNull, MaybeNull]。在可为空的上下文中没有? 同样意味着[DisallowNull, NotNull]。对于您的Null 方法,由于NotNull 的手动指定,我们最终得到[AllowNull, NotNull]

【讨论】:

感谢 Drew,这真的比 !-operator 更干净。我以前使用过 Resharper,很高兴看到我现在可以在没有它的情况下使用此属性。 这适用于字符串,但不适用于 Guid,有什么解决方案吗? Guid是值类型,不能为null。 当然,我的意思是Guid?如果通过指导?到带有 [Not Null] 的方法来检查 null 并抛出,代码分析不会选择它已被检查,并且在方法调用后分配给 Guid 时仍然抱怨。 @AndreasKoder 抱歉忘记标记你,请阅读我上面的回复^^^【参考方案2】:

好的,看起来有一个非常简单的解决方案 - the ! operator 你必须在守卫之后使用它一次,然后它认为它不为空:

public void Foo(string? argument)

    GuardAgainst.Null(argument, nameof(argument));
    var length = argument!.Length; 

【讨论】:

【参考方案3】:

考虑使用 null 合并运算符 ?? 的解决方案

空合并运算符 ??返回其左手的值 如果操作数不为空;否则,它评估右手 操作数并返回其结果。这 ??运营商不评估其 如果左侧操作数的计算结果为非空,则为右侧操作数。

public void Foo(string? argument)

    string variable = argument ?? throw new ArgumentNullException(nameof(argument));
    var length = argument.Length;

在我看来,这个解决方案要干净得多。您避免检查 GuardAgainst 类和 .Null() 静态方法实现细节。

【讨论】:

以上是关于如何抑制可能的空引用警告的主要内容,如果未能解决你的问题,请参考以下文章

EntityTypeBuilder.HasOne.WithOne 中可能的空引用返回

cppcheck : 可能的空点取消引用

如何修复或抑制误报“您可能在组件渲染函数中有无限更新循环”Vue 警告

如何抑制有关 C++ 中未使用变量的警告?

可空引用类型意外 CS8629 可空值类型可能为带有临时变量的空

如何在 Kotlin 中抑制检查式警告