CA1062:验证公共方法的参数

属性
规则 ID CA1062
标题 验证公共方法的参数
类别 设计
修复是中断修复还是非中断修复 非中断
在 .NET 8 中默认启用

原因

外部可见方法取消引用其中一个引用参数,而不验证该参数是否 null(Visual Basic 中 Nothing)。

可以将此规则配置为从分析中排除某些类型和参数。 还可以指示 null 检查验证方法

规则说明

对于传递给外部可见方法的所有引用参数,都应检查其是否为 null。 如果需要,则在参数为 null 时引发 ArgumentNullException

如果某个方法由于被声明为公共或受保护而可以从未知程序集进行调用,则应验证该方法的所有参数。 如果该方法设计为仅由已知程序集调用,请将方法标记为 internal并将 InternalsVisibleToAttribute 特性应用于包含该方法的程序集。

如何解决冲突

若要修复与此规则的冲突,请验证每个引用参数是否为 null

何时禁止显示警告

如果确定取消引用的参数已由函数中的其他方法调用进行验证,则可以禁止显示此规则发出的警告。

抑制警告

如果只想抑制单个冲突,请将预处理器指令添加到源文件以禁用该规则,然后重新启用该规则。

#pragma warning disable CA1062
// The code that's violating the rule is on this line.
#pragma warning restore CA1062

若要对文件、文件夹或项目禁用该规则,请在配置文件中将其严重性设置为 none

[*.{cs,vb}]
dotnet_diagnostic.CA1062.severity = none

有关详细信息,请参阅如何禁止显示代码分析警告

配置代码以进行分析

使用下面的选项来配置代码库的哪些部分要运行此规则。

可以仅为此规则、为适用的所有规则或为适用的此类别(设计)中的所有规则配置这些选项。 有关详细信息,请参阅代码质量规则配置选项

包含特定的 API 图面

你可以根据代码库的可访问性,配置要针对其运行此规则的部分。 例如,若要指定规则应仅针对非公共 API 图面运行,请将以下键值对添加到项目中的 .editorconfig 文件:

dotnet_code_quality.CAXXXX.api_surface = private, internal

注意

仅 .NET 7 及更高版本中的 CA1062 支持此选项。

排除特定符号

可以从分析中排除特定符号,如类型和方法。 例如,若要指定规则不应针对名为 MyType 的类型中的任何代码运行,请将以下键值对添加到项目中的 .editorconfig 文件:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

选项值中允许的符号名称格式(用 | 分隔):

  • 仅符号名称(包括具有相应名称的所有符号,不考虑包含的类型或命名空间)。
  • 完全限定的名称,使用符号的文档 ID 格式。 每个符号名称都需要带有一个符号类型前缀,例如表示方法的 M:、表示类型的 T:,以及表示命名空间的 N:
  • .ctor 表示构造函数,.cctor 表示静态构造函数。

示例:

选项值 总结
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType 匹配名为 MyType 的所有符号。
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 匹配名为 MyType1MyType2 的所有符号。
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) 匹配带有指定的完全限定签名的特定方法 MyMethod
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) 匹配带有各自的完全限定签名的特定方法 MyMethod1MyMethod2

排除特定类型及其派生类型

可以从分析中排除特定类型及其派生类型。 例如,若要指定规则不应针对名为 MyType 的类型及其派生类型中的任何代码运行,请将以下键值对添加到项目中的 .editorconfig 文件:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

选项值中允许的符号名称格式(用 | 分隔):

  • 仅类型名称(包括具有相应名称的所有类型,不考虑包含的类型或命名空间)。
  • 完全限定的名称,使用符号的文档 ID 格式,前缀为 T:(可选)。

示例:

选项值 总结
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType 匹配名为 MyType 的所有类型及其所有派生类型。
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 匹配名为 MyType1MyType2 的所有类型及其所有派生类型。
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType 匹配带有给定的完全限定名称的特定类型 MyType 及其所有派生类型。
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 匹配带有各自的完全限定名称的特定类型 MyType1MyType2 及其所有派生类型。

排除扩展方法“this”参数

默认情况下,此规则分析并标记扩展方法的 this 参数。 可以通过将以下键值对添加到项目中的 editorconfig 文件,排除扩展方法的 this 参数的分析:

dotnet_code_quality.CA1062.exclude_extension_method_this_parameter = true

Null 检查验证方法

如果代码在引用的库或项目中调用了特殊的 null 检查验证方法,则此规则可能导致误报。 可以通过指定 null 检查验证方法的名称或签名来避免这种误报。 此分析假定在调用后传递给这些方法的参数为非 null。 例如,若要将名为 Validate 的所有方法标记为 null 检查验证方法,请将以下键值对添加到项目中的 editorconfig 文件:

dotnet_code_quality.CA1062.null_check_validation_methods = Validate

选项值中允许的方法名称格式(用 | 分隔):

  • 仅方法名称(包括具有相应名称的所有方法,不考虑包含的类型或命名空间)。
  • 完全限定的名称,使用符号的文档 ID 格式,前缀为 M:(可选)。

示例:

选项值 总结
dotnet_code_quality.CA1062.null_check_validation_methods = Validate 匹配编译中所有名为 Validate 的方法。
dotnet_code_quality.CA1062.null_check_validation_methods = Validate1|Validate2 匹配编译中所有名为 Validate1Validate2 的方法。
dotnet_code_quality.CA1062.null_check_validation_methods = NS.MyType.Validate(ParamType) 将特定方法 Validate 与给定的完全限定签名相匹配。
dotnet_code_quality.CA1062.null_check_validation_methods = NS1.MyType1.Validate1(ParamType)|NS2.MyType2.Validate2(ParamType) 将特定方法 Validate1Validate2 与相应的完全限定签名相匹配。

示例 1

下面的示例演示了违反规则的方法和符合规则的方法。

using System;

namespace DesignLibrary
{
    public class Test
    {
        // This method violates the rule.
        public void DoNotValidate(string input)
        {
            if (input.Length != 0)
            {
                Console.WriteLine(input);
            }
        }

        // This method satisfies the rule.
        public void Validate(string input)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }
            if (input.Length != 0)
            {
                Console.WriteLine(input);
            }
        }
    }
}
Imports System

Namespace DesignLibrary

    Public Class Test

        ' This method violates the rule.
        Sub DoNotValidate(ByVal input As String)

            If input.Length <> 0 Then
                Console.WriteLine(input)
            End If

        End Sub

        ' This method satisfies the rule.
        Sub Validate(ByVal input As String)

            If input Is Nothing Then
                Throw New ArgumentNullException(NameOf(input))
            End If

            If input.Length <> 0 Then
                Console.WriteLine(input)
            End If

        End Sub

    End Class

End Namespace

示例 2

填充为引用对象的字段或属性的复制构造函数也可能与 CA1062 规则发生冲突。 发生冲突的原因是,传递到复制构造函数的所复制对象可能为 null(在 Visual Basic 中为 Nothing)。 若要解决冲突,请使用 static(在 Visual Basic 中为 Shared)方法来检查复制的对象是否不为 null。

在下面的 Person 类示例中,传递给 Person 复制构造函数的 other 对象可能为 null

public class Person
{
    public string Name { get; private set; }
    public int Age { get; private set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    // Copy constructor CA1062 fires because other is dereferenced
    // without being checked for null
    public Person(Person other)
        : this(other.Name, other.Age)
    {
    }
}

示例 3

在下面经修订的 Person 示例中,系统首先会在 PassThroughNonNull 方法中检查传递给复制构造函数的 other 对象是否为 null。

public class Person
{
    public string Name { get; private set; }
    public int Age { get; private set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    // Copy constructor
    public Person(Person other)
        : this(PassThroughNonNull(other).Name, other.Age)
    {
    }

    // Null check method
    private static Person PassThroughNonNull(Person person)
    {
        if (person == null)
            throw new ArgumentNullException(nameof(person));
        return person;
    }
}