Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

An attribute in C# is a declarative tag used to associate metadata with program elements such as assemblies, types, methods, properties, and fields. During compilation, the C# compiler bakes this metadata into the assembly’s metadata tables, which are distinct from the Common Intermediate Language (CIL) instruction stream. This embedded metadata does not directly affect the execution of the code but can be inspected and acted upon at runtime using Reflection.

Syntax

Attributes are applied by enclosing the attribute name and its arguments in square brackets [] immediately above the target element.
[AttributeName(positionalArgument, NamedArgument = value)]
public class TargetElement 
{
    [AttributeName]
    public void TargetMethod() { }
}
By convention, all attribute class names end with the word Attribute. The C# compiler allows you to omit this suffix when applying the attribute in code (e.g., [Obsolete] instead of [ObsoleteAttribute]).

Anatomy of a Custom Attribute

Under the hood, an attribute is simply a class that inherits directly or indirectly from the System.Attribute base class.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public sealed class MetadataAttribute : System.Attribute
{
    // Positional parameter (Constructor argument)
    public MetadataAttribute(string author)
    {
        Author = author;
    }

    public string Author { get; }

    // Named parameter (Public read-write property)
    public string Version { get; set; }
}

Parameter Types

Attribute parameters are strictly limited by the compiler. They can only be:
  • Simple types (bool, byte, sbyte, char, short, ushort, int, uint, long, ulong, float, double)
  • string
  • System.Type
  • Enums
  • object (though the actual argument passed at compile-time must evaluate to one of the other permitted types)
  • Single-dimensional arrays of any of the above

Positional vs. Named Parameters

When applying an attribute, arguments are passed based on the attribute class’s design:
  1. Positional Parameters: These map directly to the constructor signatures of the attribute class. They are mandatory and must be specified in the exact order defined by the constructor.
  2. Named Parameters: These map to public, non-static, read-write fields or properties on the attribute class. They are optional and are specified using the PropertyName = value syntax after all positional parameters.
// "Alice" is positional; Version is named.
[Metadata("Alice", Version = "1.0.0")] 
public class Processor { }

The [AttributeUsage] Meta-Attribute

When defining a custom attribute, its behavior and valid application targets are governed by applying the System.AttributeUsageAttribute to the custom attribute class itself. It accepts three configurations:
  1. ValidOn (AttributeTargets): A bitwise combination of AttributeTargets enum values (e.g., Class, Method, Property, All) dictating exactly which code elements the compiler will allow the attribute to be attached to.
  2. AllowMultiple (bool): Determines whether the same attribute can be applied more than once to a single program element.
  3. Inherited (bool): Determines whether the attribute is automatically inherited by derived classes or overriding methods.

Metadata Retrieval

Because attributes are compiled into the assembly’s metadata tables, they remain dormant until explicitly queried. The .NET runtime provides Reflection APIs, primarily through the System.Reflection.MemberInfo.GetCustomAttributes method, to instantiate and read the attribute objects at runtime.
Type targetType = typeof(Processor);

// Extracts the attribute metadata from the compiled assembly
object[] attributes = targetType.GetCustomAttributes(typeof(MetadataAttribute), false);

foreach (MetadataAttribute attr in attributes)
{
    Console.WriteLine($"Author: {attr.Author}, Version: {attr.Version}");
}
Master C# with Deep Grasping Methodology!Learn More