C#idiomatic C#
creating-custom-attributescsharp/advanced-topics/reflection-and-attributes

Advanced

Create custom attributes

Learn how to create custom attributes in C# by defining an attribute class that derives from the Attribute class.

  • page csharp/advanced-topics/reflection-and-attributes/creating-custom-attributes
  • updated 03/15/2023

You can create your own custom attributes by defining an attribute class, a class that derives directly or indirectly from System.Attribute, which makes identifying attribute definitions in metadata fast and easy. Suppose you want to tag types with the name of the programmer who wrote the type. You might define a custom Author attribute class:

csharp
[System.AttributeUsage(System.AttributeTargets.Class |
                       System.AttributeTargets.Struct)
]
public class AuthorAttribute : System.Attribute
{
    private string Name;
    public string Version;

    public AuthorAttribute(string name)
    {
        Name = name;
        Version = "1.0";
    }
}

The class name AuthorAttribute is the attribute's name, Author, plus the Attribute suffix. It's derived from System.Attribute, so it's a custom attribute class. The constructor's parameters are the custom attribute's positional parameters. In this example, name is a positional parameter. Any public read-write fields or properties are named parameters. In this case, version is the only named parameter. Note the use of the AttributeUsage attribute to make the Author attribute valid only on class and struct declarations.

You could use this new attribute as follows:

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/ReadAttributes.csSampleWithVersion

csharp
namespace ReflectionExamples;

// <DefineAndReadAttribute>
// Multiuse attribute.
// <DefineCustomAttribute>
[System.AttributeUsage(System.AttributeTargets.Class |
                       System.AttributeTargets.Struct,
                       AllowMultiple = true)  // Multiuse attribute.
]
public class AuthorAttribute : System.Attribute
{
    string Name;
    public string Version;

    public AuthorAttribute(string name)
    {
        Name = name;

        // Default value.
        Version = "1.0";
    }

    public string GetName() => Name;
}
// </DefineCustomAttribute>

// Class with the Author attribute.
[Author("P. Ackerman")]
public class FirstClass
{
    // ...
}

// Class without the Author attribute.
public class SecondClass
{
    // ...
}

// Class with multiple Author attributes.
// <MultipleAuthors>
[Author("P. Ackerman"), Author("R. Koch", Version = "2.0")]
public class ThirdClass
{
    // ...
}
// </MultipleAuthors>

class TestAuthorAttribute
{
    public static void Test()
    {
        PrintAuthorInfo(typeof(FirstClass));
        PrintAuthorInfo(typeof(SecondClass));
        PrintAuthorInfo(typeof(ThirdClass));
    }

    private static void PrintAuthorInfo(System.Type t)
    {
        System.Console.WriteLine($"Author information for {t}");

        // Using reflection.
        System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // Reflection.

        // Displaying output.
        foreach (System.Attribute attr in attrs)
        {
            if (attr is AuthorAttribute a)
            {
                System.Console.WriteLine($"   {a.GetName()}, version {a.Version}");
            }
        }
    }
}
/* Output:
    Author information for FirstClass
       P. Ackerman, version 1.0
    Author information for SecondClass
    Author information for ThirdClass
       R. Koch, version 2.0
       P. Ackerman, version 1.0
*/
// </DefineAndReadAttribute>

// <SampleWithVersion>
[Author("P. Ackerman", Version = "1.1")]
class SampleClass
{
    // P. Ackerman's code goes here...
}
// </SampleWithVersion>

AttributeUsage has a named parameter, AllowMultiple, with which you can make a custom attribute single-use or multiuse. In the following code example, a multiuse attribute is created.

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/ReadAttributes.csDefineCustomAttribute

csharp
namespace ReflectionExamples;

// <DefineAndReadAttribute>
// Multiuse attribute.
// <DefineCustomAttribute>
[System.AttributeUsage(System.AttributeTargets.Class |
                       System.AttributeTargets.Struct,
                       AllowMultiple = true)  // Multiuse attribute.
]
public class AuthorAttribute : System.Attribute
{
    string Name;
    public string Version;

    public AuthorAttribute(string name)
    {
        Name = name;

        // Default value.
        Version = "1.0";
    }

    public string GetName() => Name;
}
// </DefineCustomAttribute>

// Class with the Author attribute.
[Author("P. Ackerman")]
public class FirstClass
{
    // ...
}

// Class without the Author attribute.
public class SecondClass
{
    // ...
}

// Class with multiple Author attributes.
// <MultipleAuthors>
[Author("P. Ackerman"), Author("R. Koch", Version = "2.0")]
public class ThirdClass
{
    // ...
}
// </MultipleAuthors>

class TestAuthorAttribute
{
    public static void Test()
    {
        PrintAuthorInfo(typeof(FirstClass));
        PrintAuthorInfo(typeof(SecondClass));
        PrintAuthorInfo(typeof(ThirdClass));
    }

    private static void PrintAuthorInfo(System.Type t)
    {
        System.Console.WriteLine($"Author information for {t}");

        // Using reflection.
        System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // Reflection.

        // Displaying output.
        foreach (System.Attribute attr in attrs)
        {
            if (attr is AuthorAttribute a)
            {
                System.Console.WriteLine($"   {a.GetName()}, version {a.Version}");
            }
        }
    }
}
/* Output:
    Author information for FirstClass
       P. Ackerman, version 1.0
    Author information for SecondClass
    Author information for ThirdClass
       R. Koch, version 2.0
       P. Ackerman, version 1.0
*/
// </DefineAndReadAttribute>

// <SampleWithVersion>
[Author("P. Ackerman", Version = "1.1")]
class SampleClass
{
    // P. Ackerman's code goes here...
}
// </SampleWithVersion>

In the following code example, multiple attributes of the same type are applied to a class.

sample · csharpdocs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/ReadAttributes.csMultipleAuthors

csharp
namespace ReflectionExamples;

// <DefineAndReadAttribute>
// Multiuse attribute.
// <DefineCustomAttribute>
[System.AttributeUsage(System.AttributeTargets.Class |
                       System.AttributeTargets.Struct,
                       AllowMultiple = true)  // Multiuse attribute.
]
public class AuthorAttribute : System.Attribute
{
    string Name;
    public string Version;

    public AuthorAttribute(string name)
    {
        Name = name;

        // Default value.
        Version = "1.0";
    }

    public string GetName() => Name;
}
// </DefineCustomAttribute>

// Class with the Author attribute.
[Author("P. Ackerman")]
public class FirstClass
{
    // ...
}

// Class without the Author attribute.
public class SecondClass
{
    // ...
}

// Class with multiple Author attributes.
// <MultipleAuthors>
[Author("P. Ackerman"), Author("R. Koch", Version = "2.0")]
public class ThirdClass
{
    // ...
}
// </MultipleAuthors>

class TestAuthorAttribute
{
    public static void Test()
    {
        PrintAuthorInfo(typeof(FirstClass));
        PrintAuthorInfo(typeof(SecondClass));
        PrintAuthorInfo(typeof(ThirdClass));
    }

    private static void PrintAuthorInfo(System.Type t)
    {
        System.Console.WriteLine($"Author information for {t}");

        // Using reflection.
        System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // Reflection.

        // Displaying output.
        foreach (System.Attribute attr in attrs)
        {
            if (attr is AuthorAttribute a)
            {
                System.Console.WriteLine($"   {a.GetName()}, version {a.Version}");
            }
        }
    }
}
/* Output:
    Author information for FirstClass
       P. Ackerman, version 1.0
    Author information for SecondClass
    Author information for ThirdClass
       R. Koch, version 2.0
       P. Ackerman, version 1.0
*/
// </DefineAndReadAttribute>

// <SampleWithVersion>
[Author("P. Ackerman", Version = "1.1")]
class SampleClass
{
    // P. Ackerman's code goes here...
}
// </SampleWithVersion>

See also