CA2208:正确实例化参数异常

属性
规则 ID CA2208
标题 正确实例化参数异常
类别 使用情况
修复是中断修复还是非中断修复 非中断
在 .NET 10 中默认启用 作为建议

原因

如果方法具有参数,并且引发了异常类型 ArgumentException 或其派生类型,则它应正确调用接受 paramName 参数的构造函数。 可能的原因包括以下情况:

  • 对异常类型的默认(无参数)构造函数进行调用,该构造函数也具有接受ArgumentException参数的构造函数(或派生自paramName该构造函数)。
  • 向异常类型 ArgumentException 或其派生类型的参数化构造函数传递了错误的字符串参数。 例如,该 paramName 参数与方法的参数之一的名称不匹配。
  • 要为一种异常类型的构造函数(该异常类型是 message 或从 message 派生而来)的参数传递参数名称。

规则说明

请勿调用默认构造函数,而是调用允许提供更有意义的异常消息的构造函数重载之一。 异常消息应面向开发人员,并清楚地说明错误情况以及如何纠正或避免异常。

ArgumentException 及其派生类型的一个和两个字符串构造函数的签名与 messageparamName 参数位置不一致。 确保使用正确的字符串参数调用这些构造函数。 签名如下:

如何解决冲突

若要解决此规则的冲突,请调用使用消息和/或参数名称的构造函数,并确保参数对于要调用的 ArgumentException 类型是正确的。

提示

Visual Studio 中提供了针对参数名称位置错误的代码修补程序。 若要使用它,请将光标置于警告行上,然后按“Ctrl.”(句点)。 从显示的选项列表中选择“交换参数顺序”。

CA2208 的代码修补程序 - 交换参数。

如果将参数名而不是消息传递给 ArgumentException(String) 方法,修补程序将改为提供切换到双参数构造函数的选项。

CA2208 的代码修补程序 - 切换到双参数构造函数。

何时禁止显示警告

仅当使用正确的字符串参数调用参数化构造函数时,才可禁止显示此规则的警告。

抑制警告

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

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

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

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

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

配置代码以进行分析

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

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

包含特定的 API 图面

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

dotnet_code_quality.CAXXXX.api_surface = private, internal

注意

XXXXCAXXXX 部分替换为适用规则的 ID。

默认情况下,CA2208 规则适用于所有 API 图面(公共、内部和私有)。

示例

下面的代码演示了一个错误地实例化 ArgumentNullException 实例的构造函数。

public class Book
{
    public Book(string title)
    {
        Title = title ??
            throw new ArgumentNullException("All books must have a title.", nameof(title));
    }

    public string Title { get; }
}
Public Class Book

    Private ReadOnly _Title As String

    Public Sub New(ByVal title As String)
        ' Violates this rule (constructor arguments are switched)            
        If (title Is Nothing) Then
            Throw New ArgumentNullException("title cannot be a null reference (Nothing in Visual Basic)", "title")
        End If
        _Title = title
    End Sub

    Public ReadOnly Property Title()
        Get
            Return _Title
        End Get
    End Property

End Class

下面的代码通过切换构造函数参数来解决前面的冲突。

public class Book
{
    public Book(string title)
    {
        Title = title ??
            throw new ArgumentNullException(nameof(title), "All books must have a title.");
    }

    public string Title { get; }
}
Public Class Book

    Private ReadOnly _Title As String

    Public Sub New(ByVal title As String)
        If (title Is Nothing) Then
            Throw New ArgumentNullException("title", "title cannot be a null reference (Nothing in Visual Basic)")
        End If

        _Title = title
    End Sub

    Public ReadOnly Property Title()
        Get
            Return _Title
        End Get
    End Property

End Class

下面的代码显示了一个方法错误地引发ArgumentNullException,其中paramName与该方法的任何参数都不匹配。 规则触发是因为 description 是局部变量,而不是方法参数。

public class Product
{
    public string? Description { get; set; }
    public string Name { get; set; } = string.Empty;
}

public class Example
{
    // Violates CA2208: 'description' is not a parameter of this method.
    public void ProcessProduct(Product product)
    {
        string? description = product.Description;
        if (description is null)
        {
            throw new ArgumentNullException(nameof(description), $"Product named {product.Name} had no description!");
        }
        // Process description...
    }
}
Public Class Product
    Public Property Description As String
    Public Property Name As String = String.Empty
End Class

Public Class Example
    ' Violates CA2208: 'description' is not a parameter of this method.
    Public Sub ProcessProduct(ByVal product As Product)
        Dim description As String = product.Description
        If description Is Nothing Then
            Throw New ArgumentNullException(NameOf(description), $"Product named {product.Name} had no description!")
        End If
        ' Process description...
    End Sub
End Class

以下代码使用 InvalidOperationException 替代以解决以前的违规情况,当对象的状态无效时,此代码是适合的选择。

public class Product
{
    public string? Description { get; set; }
    public string Name { get; set; } = string.Empty;
}

public class Example
{
    // Fixed: Use InvalidOperationException for invalid object state.
    public void ProcessProduct(Product product)
    {
        string? description = product.Description;
        if (description is null)
        {
            throw new InvalidOperationException($"Product named {product.Name} had no description!");
        }
        // Process description...
    }
}
Public Class Product
    Public Property Description As String
    Public Property Name As String = String.Empty
End Class

Public Class Example
    ' Fixed: Use InvalidOperationException for invalid object state.
    Public Sub ProcessProduct(ByVal product As Product)
        Dim description As String = product.Description
        If description Is Nothing Then
            Throw New InvalidOperationException($"Product named {product.Name} had no description!")
        End If
        ' Process description...
    End Sub
End Class