CA1018: Mark attributes with AttributeUsageAttribute

Property Value
Rule ID CA1018
Title Mark attributes with AttributeUsageAttribute
Category Design
Fix is breaking or non-breaking Breaking
Enabled by default in .NET 8 As suggestion

Cause

The System.AttributeUsageAttribute attribute is not present on the custom attribute.

Rule description

When you define a custom attribute, mark it by using AttributeUsageAttribute to indicate where in the source code the custom attribute can be applied. The meaning and intended usage of an attribute will determine its valid locations in code. For example, you might define an attribute that identifies the person who is responsible for maintaining and enhancing each type in a library, and that responsibility is always assigned at the type level. In this case, compilers should enable the attribute on classes, enumerations, and interfaces, but should not enable it on methods, events, or properties. Organizational policies and procedures would dictate whether the attribute should be enabled on assemblies.

The System.AttributeTargets enumeration defines the targets that you can specify for a custom attribute. If you omit AttributeUsageAttribute, your custom attribute will be valid for all targets, as defined by the All value of AttributeTargets enumeration.

How to fix violations

To fix a violation of this rule, specify targets for the attribute by using AttributeUsageAttribute. See the following example.

When to suppress warnings

You should fix a violation of this rule instead of excluding the message. Even if the attribute inherits AttributeUsageAttribute, the attribute should be present to simplify code maintenance.

Example

The following example defines two attributes. BadCodeMaintainerAttribute incorrectly omits the AttributeUsageAttribute statement, and GoodCodeMaintainerAttribute correctly implements the attribute that is described earlier in this section. (The property DeveloperName is required by the design rule CA1019: Define accessors for attribute arguments and is included for completeness.)

using System;

namespace ca1018
{
    // Violates rule: MarkAttributesWithAttributeUsage.
    public sealed class BadCodeMaintainerAttribute : Attribute
    {
        public BadCodeMaintainerAttribute(string developerName)
        {
            DeveloperName = developerName;
        }
        public string DeveloperName { get; }
    }

    // Satisfies rule: Attributes specify AttributeUsage.
    // This attribute is valid for type-level targets.
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate)]
    public sealed class GoodCodeMaintainerAttribute : Attribute
    {
        public GoodCodeMaintainerAttribute(string developerName)
        {
            DeveloperName = developerName;
        }
        public string DeveloperName { get; }
    }
}
Imports System

Namespace ca1018

    ' Violates rule: MarkAttributesWithAttributeUsage.
    Public NotInheritable Class BadCodeMaintainerAttribute
        Inherits Attribute

        Public Sub New(developerName As String)
            Me.DeveloperName = developerName
        End Sub 'New

        Public ReadOnly Property DeveloperName() As String
    End Class

    ' Satisfies rule: Attributes specify AttributeUsage.
    ' The attribute is valid for type-level targets.
    <AttributeUsage(AttributeTargets.Class Or AttributeTargets.Enum Or
   AttributeTargets.Interface Or AttributeTargets.Delegate)>
    Public NotInheritable Class GoodCodeMaintainerAttribute
        Inherits Attribute

        Public Sub New(developerName As String)
            Me.DeveloperName = developerName
        End Sub 'New

        Public ReadOnly Property DeveloperName() As String
    End Class

End Namespace

See also