Mark attributes with AttributeUsageAttribute

TypeName

MarkAttributesWithAttributeUsage

CheckId

CA1018

Category

Microsoft.Design

Breaking Change

Breaking

Cause

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

Rule Description

When defining a custom attribute, mark it using AttributeUsageAttribute to indicate where in the source code the custom attribute can be applied. An attribute's meaning and intended usage will determine its valid locations in code. For example, if you are defining an attribute that identifies the person responsible for maintaining and enhancing each type in a library, and responsibility is always assigned at the type level, compilers should allow the attribute on classes, enumerations, and interfaces, but should not allow it on methods, events, or properties. Organizational policies and procedures would dictate whether the attribute should be allowed on assemblies.

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

How to Fix Violations

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

When to Exclude 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, while GoodCodeMaintainerAttribute correctly implements the attribute described above. Note that the property DeveloperName is required by the design rule Define accessors for attribute arguments and is included for completeness.

Imports System

Namespace DesignLibrary

' Violates rule: MarkAttributesWithAttributeUsage.
NotInheritable Public Class BadCodeMaintainerAttribute
    Inherits Attribute
    Private developer As String
    
    Public Sub New(developerName As String)
        developer = developerName
    End Sub 'New
    
    Public ReadOnly Property DeveloperName() As String
        Get
            Return developer
        End Get
    End Property
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)> _
NotInheritable Public Class GoodCodeMaintainerAttribute
    Inherits Attribute
    Private developer As String
    
    Public Sub New(developerName As String)
        developer = developerName
    End Sub 'New
    
    Public ReadOnly Property DeveloperName() As String
        Get
            Return developer
        End Get
    End Property
End Class 

End Namespace
using System;

namespace DesignLibrary
{
// Violates rule: MarkAttributesWithAttributeUsage.

   public sealed class BadCodeMaintainerAttribute :Attribute 
   {
      string developer;

      public BadCodeMaintainerAttribute(string developerName)
      {
         developer = developerName;
      }
      public string DeveloperName
      {
         get 
         {
            return developer;
         }
      }
   }
// Satisfies rule: Attributes specify AttributeUsage.

   // The attribute is valid for type-level targets.
   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate)]
   public sealed class GoodCodeMaintainerAttribute :Attribute 
   {
      string developer;

      public GoodCodeMaintainerAttribute(string developerName)
      {
         developer = developerName;
      }
      public string DeveloperName
      {
         get 
         {
            return developer;
         }
      }
   }
}

Define accessors for attribute arguments

Avoid unsealed attributes

See Also

Reference

Attribute Usage Guidelines
System.AttributeTargets