🎓 A1Learner
🔍
0 of 28 lessons completed

C# Custom Attributes

A custom attribute is a class that derives from Attribute and carries data of its own. Other code applies it like a built-in marker and reads its data back with reflection.

Defining and applying a marker

InfoAttribute stores an author name through its constructor. The [Info] use above Report applies the marker to the class.

using System;

[AttributeUsage(AttributeTargets.Class)]
class InfoAttribute : Attribute
{
    public string Author { get; }

    public InfoAttribute(string author)
    {
        Author = author;
    }
}

[Info("Hana")]
class Report
{
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(typeof(Report).Name);
    }
}

Reading the data back

GetCustomAttribute<InfoAttribute> returns the stored attribute object. Its Author property holds the constructor value.

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Class)]
class InfoAttribute : Attribute
{
    public string Author { get; }

    public InfoAttribute(string author)
    {
        Author = author;
    }
}

[Info("Hana")]
class Report
{
}

class Program
{
    static void Main(string[] args)
    {
        InfoAttribute info = typeof(Report).GetCustomAttribute<InfoAttribute>();
        Console.WriteLine(info.Author);
    }
}

A named argument

Level is a settable property, so the use site sets it with a named argument. The constructor value and the property value both read back.

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Class)]
class InfoAttribute : Attribute
{
    public string Author { get; }
    public int Level { get; set; }

    public InfoAttribute(string author)
    {
        Author = author;
    }
}

[Info("Hana", Level = 2)]
class Report
{
}

class Program
{
    static void Main(string[] args)
    {
        InfoAttribute info = typeof(Report).GetCustomAttribute<InfoAttribute>();
        Console.WriteLine(info.Author);
        Console.WriteLine(info.Level);
    }
}

Example

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Class)]
class InfoAttribute : Attribute
{
    public string Author { get; }

    public InfoAttribute(string author)
    {
        Author = author;
    }
}

[Info("Omar")]
class Table
{
}

[Info("Mina")]
class Chart
{
}

class Program
{
    static void Main(string[] args)
    {
        Type[] types = { typeof(Table), typeof(Chart) };
        Array.Sort(types, (a, b) => string.Compare(a.Name, b.Name));
        foreach (Type type in types)
        {
            InfoAttribute info = type.GetCustomAttribute<InfoAttribute>();
            Console.WriteLine(info.Author);
        }
    }
}

Key points

  • A custom attribute class derives from the Attribute base class.
  • The AttributeUsage attribute on it states which targets it may mark.
  • AttributeTargets.Class restricts a marker to classes.
  • Constructor arguments become the positional data stored in each use of the marker.
  • A public settable property becomes a named argument, written as Name = value at the use site.
  • GetCustomAttribute<T> reads one marker back from a type and returns the attribute object.
  • The using System.Reflection line brings in GetCustomAttribute.

In this example, two classes each carry an [Info] marker with a different author. Main collects the two types and sorts them by name. The loop reads each marker back with GetCustomAttribute. The authors print in class name order.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What must a class do to serve as a custom attribute?