CA1019: Define accessors for attribute arguments
Property | Value |
---|---|
Rule ID | CA1019 |
Title | Define accessors for attribute arguments |
Category | Design |
Fix is breaking or non-breaking | Non-breaking |
Enabled by default in .NET 8 | No |
Cause
In its constructor, an attribute defines arguments that do not have corresponding properties.
Rule description
Attributes can define mandatory arguments that must be specified when you apply the attribute to a target. These are also known as positional arguments because they are supplied to attribute constructors as positional parameters. For every mandatory argument, the attribute should also provide a corresponding read-only property so that the value of the argument can be retrieved at execution time. This rule checks that for each constructor parameter, you have defined the corresponding property.
Attributes can also define optional arguments, which are also known as named arguments. These arguments are supplied to attribute constructors by name and should have a corresponding read/write property.
For mandatory and optional arguments, the corresponding properties and constructor parameters should use the same name but different casing. Properties use Pascal casing, and parameters use camel casing.
How to fix violations
To fix a violation of this rule, add a read-only property for each constructor parameter that does not have one.
When to suppress warnings
Suppress a warning from this rule if you do not want the value of the mandatory argument to be retrievable.
Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
#pragma warning disable CA1019
// The code that's violating the rule is on this line.
#pragma warning restore CA1019
To disable the rule for a file, folder, or project, set its severity to none
in the configuration file.
[*.{cs,vb}]
dotnet_diagnostic.CA1019.severity = none
For more information, see How to suppress code analysis warnings.
Examples
Custom attributes
The following example shows two attributes that define a mandatory (positional) parameter. The first implementation of the attribute is incorrectly defined. The second implementation is correct.
// Violates rule: DefineAccessorsForAttributeArguments.
[AttributeUsage(AttributeTargets.All)]
public sealed class BadCustomAttribute : Attribute
{
string _data;
// Missing the property that corresponds to
// the someStringData constructor parameter.
public BadCustomAttribute(string someStringData)
{
_data = someStringData;
}
}
// Satisfies rule: Attributes should have accessors for all arguments.
[AttributeUsage(AttributeTargets.All)]
public sealed class GoodCustomAttribute : Attribute
{
public GoodCustomAttribute(string someStringData)
{
SomeStringData = someStringData;
}
//The constructor parameter and property
//name are the same except for case.
public string SomeStringData { get; }
}
Imports System
Namespace ca1019
' Violates rule: DefineAccessorsForAttributeArguments.
<AttributeUsage(AttributeTargets.All)>
Public NotInheritable Class BadCustomAttribute
Inherits Attribute
Private data As String
' Missing the property that corresponds to
' the someStringData parameter.
Public Sub New(someStringData As String)
data = someStringData
End Sub 'New
End Class 'BadCustomAttribute
' Satisfies rule: Attributes should have accessors for all arguments.
<AttributeUsage(AttributeTargets.All)>
Public NotInheritable Class GoodCustomAttribute
Inherits Attribute
Public Sub New(someStringData As String)
Me.SomeStringData = someStringData
End Sub 'New
'The constructor parameter and property
'name are the same except for case.
Public ReadOnly Property SomeStringData() As String
End Class
End Namespace
Positional and named arguments
Positional and named arguments make it clear to consumers of your library which arguments are mandatory for the attribute and which arguments are optional.
The following example shows an implementation of an attribute that has both positional and named arguments:
[AttributeUsage(AttributeTargets.All)]
public sealed class GoodCustomAttribute : Attribute
{
public GoodCustomAttribute(string mandatoryData)
{
MandatoryData = mandatoryData;
}
public string MandatoryData { get; }
public string? OptionalData { get; set; }
}
The following example shows how to apply the custom attribute to two properties:
[GoodCustomAttribute("ThisIsSomeMandatoryData", OptionalData = "ThisIsSomeOptionalData")]
public string? MyProperty { get; set; }
[GoodCustomAttribute("ThisIsSomeMoreMandatoryData")]
public string? MyOtherProperty { get; set; }
Related rules
CA1813: Avoid unsealed attributes