Skip to content

Latest commit

 

History

History
161 lines (106 loc) · 14.1 KB

writing-custom-attributes.md

File metadata and controls

161 lines (106 loc) · 14.1 KB
title description ms.date ms.custom dev_langs helpviewer_keywords ms.assetid
Writing Custom Attributes
Design your own custom attributes in .NET. Custom attributes are essentially classes derived directly or indirectly from System.Attribute.
08/05/2022
devdivchpfy22
csharp
vb
cpp
multiple attribute instances
AttributeTargets enumeration
attributes [.NET], custom
AllowMultiple property
custom attributes
AttributeUsageAttribute class, custom attributes
Inherited property
attribute classes, declaring
97216f69-bde8-49fd-ac40-f18c500ef5dc

Write custom attributes

To design custom attributes, you don't need to learn many new concepts. If you're familiar with object-oriented programming and know how to design classes, you already have most of the knowledge needed. Custom attributes are traditional classes that derive directly or indirectly from the xref:System.Attribute?displayProperty=nameWithType class. Just like traditional classes, custom attributes contain methods that store and retrieve data.

The primary steps to properly design custom attribute classes are as follows:

This section describes each of these steps and concludes with a custom attribute example.

Applying the AttributeUsageAttribute

A custom attribute declaration begins with the xref:System.AttributeUsageAttribute?displayProperty=nameWithType attribute, which defines some of the key characteristics of your attribute class. For example, you can specify whether your attribute can be inherited by other classes or which elements the attribute can be applied to. The following code fragment demonstrates how to use the xref:System.AttributeUsageAttribute:

[!code-cppConceptual.Attributes.Usage#5] [!code-csharpConceptual.Attributes.Usage#5] [!code-vbConceptual.Attributes.Usage#5]

The xref:System.AttributeUsageAttribute has three members that are important for the creation of custom attributes: AttributeTargets, Inherited, and AllowMultiple.

AttributeTargets Member

In the preceding example, xref:System.AttributeTargets.All?displayProperty=nameWithType is specified, indicating that this attribute can be applied to all program elements. Alternatively, you can specify xref:System.AttributeTargets.Class?displayProperty=nameWithType, indicating that your attribute can be applied only to a class, or xref:System.AttributeTargets.Method?displayProperty=nameWithType, indicating that your attribute can be applied only to a method. All program elements can be marked for description by a custom attribute in this manner.

You can also pass multiple xref:System.AttributeTargets values. The following code fragment specifies that a custom attribute can be applied to any class or method:

[!code-cppConceptual.Attributes.Usage#6] [!code-csharpConceptual.Attributes.Usage#6] [!code-vbConceptual.Attributes.Usage#6]

Inherited Property

The xref:System.AttributeUsageAttribute.Inherited%2A?displayProperty=nameWithType property indicates whether your attribute can be inherited by classes that are derived from the classes to which your attribute is applied. This property takes either a true (the default) or false flag. In the following example, MyAttribute has a default xref:System.AttributeUsageAttribute.Inherited%2A value of true, while YourAttribute has an xref:System.AttributeUsageAttribute.Inherited%2A value of false:

[!code-cppConceptual.Attributes.Usage#7] [!code-csharpConceptual.Attributes.Usage#7] [!code-vbConceptual.Attributes.Usage#7]

The two attributes are then applied to a method in the base class MyClass:

[!code-cppConceptual.Attributes.Usage#9] [!code-csharpConceptual.Attributes.Usage#9] [!code-vbConceptual.Attributes.Usage#9]

Finally, the class YourClass is inherited from the base class MyClass. The method MyMethod shows MyAttribute but not YourAttribute:

[!code-cppConceptual.Attributes.Usage#10] [!code-csharpConceptual.Attributes.Usage#10] [!code-vbConceptual.Attributes.Usage#10]

AllowMultiple Property

The xref:System.AttributeUsageAttribute.AllowMultiple%2A?displayProperty=nameWithType property indicates whether multiple instances of your attribute can exist on an element. If set to true, multiple instances are allowed. If set to false (the default), only one instance is allowed.

In the following example, MyAttribute has a default xref:System.AttributeUsageAttribute.AllowMultiple%2A value of false, while YourAttribute has a value of true:

[!code-cppConceptual.Attributes.Usage#11] [!code-csharpConceptual.Attributes.Usage#11] [!code-vbConceptual.Attributes.Usage#11]

When multiple instances of these attributes are applied, MyAttribute produces a compiler error. The following code example shows the valid use of YourAttribute and the invalid use of MyAttribute:

[!code-cppConceptual.Attributes.Usage#13] [!code-csharpConceptual.Attributes.Usage#13] [!code-vbConceptual.Attributes.Usage#13]

If both the xref:System.AttributeUsageAttribute.AllowMultiple%2A property and the xref:System.AttributeUsageAttribute.Inherited%2A property are set to true, a class that's inherited from another class can inherit an attribute and have another instance of the same attribute applied in the same child class. If xref:System.AttributeUsageAttribute.AllowMultiple%2A is set to false, the values of any attributes in the parent class will be overwritten by new instances of the same attribute in the child class.

Declaring the Attribute Class

After you apply the xref:System.AttributeUsageAttribute, start defining the specifics of your attribute. The declaration of an attribute class looks similar to the declaration of a traditional class, as demonstrated by the following code:

[!code-cppConceptual.Attributes.Usage#14] [!code-csharpConceptual.Attributes.Usage#14] [!code-vbConceptual.Attributes.Usage#14]

This attribute definition demonstrates the following points:

  • Attribute classes must be declared as public classes.

  • By convention, the name of the attribute class ends with the word Attribute. While not required, this convention is recommended for readability. When the attribute is applied, the inclusion of the word Attribute is optional.

  • All attribute classes must inherit directly or indirectly from the xref:System.Attribute?displayProperty=nameWithType class.

  • In Microsoft Visual Basic, all custom attribute classes must have the xref:System.AttributeUsageAttribute?displayProperty=nameWithType attribute.

Declaring Constructors

Just like traditional classes, attributes are initialized with constructors. The following code fragment illustrates a typical attribute constructor. This public constructor takes a parameter and sets a member variable equal to its value.

[!code-cppConceptual.Attributes.Usage#15] [!code-csharpConceptual.Attributes.Usage#15] [!code-vbConceptual.Attributes.Usage#15]

You can overload the constructor to accommodate different combinations of values. If you also define a property for your custom attribute class, you can use a combination of named and positional parameters when initializing the attribute. Typically, you define all required parameters as positional and all optional parameters as named. In this case, the attribute can't be initialized without the required parameter. All other parameters are optional.

Note

In Visual Basic, constructors for an attribute class shouldn't use a ParamArray argument.

The following code example shows how an attribute that uses the previous constructor can be applied using optional and required parameters. It assumes that the attribute has one required Boolean value and one optional string property.

[!code-cppConceptual.Attributes.Usage#17] [!code-csharpConceptual.Attributes.Usage#17] [!code-vbConceptual.Attributes.Usage#17]

Declaring Properties

If you want to define a named parameter or provide an easy way to return the values stored by your attribute, declare a property. Attribute properties should be declared as public entities with a description of the data type that will be returned. Define the variable that will hold the value of your property and associate it with the get and set methods. The following code example demonstrates how to implement a property in your attribute:

[!code-cppConceptual.Attributes.Usage#16] [!code-csharpConceptual.Attributes.Usage#16] [!code-vbConceptual.Attributes.Usage#16]

Custom Attribute Example

This section incorporates the previous information and shows how to design an attribute that documents information about the author of a section of code. The attribute in this example stores the name and level of the programmer, and whether the code has been reviewed. It uses three private variables to store the actual values to save. Each variable is represented by a public property that gets and sets the values. Finally, the constructor is defined with two required parameters:

[!code-cppConceptual.Attributes.Usage#4] [!code-csharpConceptual.Attributes.Usage#4] [!code-vbConceptual.Attributes.Usage#4]

You can apply this attribute using the full name, DeveloperAttribute, or using the abbreviated name, Developer, in one of the following ways:

[!code-cppConceptual.Attributes.Usage#12] [!code-csharpConceptual.Attributes.Usage#12] [!code-vbConceptual.Attributes.Usage#12]

The first example shows the attribute applied with only the required named parameters. The second example shows the attribute applied with both the required and optional parameters.

See also