Skip to content

Attributes in C# — Complete Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Attributes in C#. We cover key concepts, practical examples, and best practices to help you master this topic.

Hook

Attributes are annotations that add metadata to types, methods, properties, and other code elements. The .NET runtime and frameworks use attributes extensively for configuration without invading your business logic. Understanding attributes lets you build declarative, clean, and extensible systems.

Learning Path

graph LR
  A[Attributes] --> B[Built-in Attributes]
  A --> C[Custom Attributes]
  B --> D[Conditional Obsolete]
  C --> E[AttributeUsage]
  C --> F[Runtime Reflection]
  style A fill:#4a90d9,color:#fff
  style B fill:#4a90d9,color:#fff
  style C fill:#4a90d9,color:#fff
  style D fill:#4a90d9,color:#fff
  style E fill:#4a90d9,color:#fff
  style F fill:#4a90d9,color:#fff

Built-in Attributes

C# provides many built-in attributes for common scenarios.

using System;
using System.Diagnostics;

[Obsolete("Use NewMethod instead")]
public static void OldMethod() => Console.WriteLine("Old");

public static void NewMethod() => Console.WriteLine("New");

[Conditional("DEBUG")]
public static void DebugOnlyMethod()
{
    Console.WriteLine("Only in Debug builds");
}

public class MyClass
{
    // CLSCompliant ensures cross-language compatibility
    [CLSCompliant(true)]
    public void SafeMethod() { }
}

When you call OldMethod, the compiler shows a warning but still compiles.

Creating Custom Attributes

Custom attributes are classes that inherit from System.Attribute.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public class AuthorAttribute : Attribute
{
    public string Name { get; }
    public string? Version { get; set; }

    public AuthorAttribute(string name)
    {
        Name = name;
    }
}

[Author("Alice", Version = "1.0")]
[Author("Bob")]
public class SampleClass
{
    [Author("Charlie")]
    public void DoWork() { }
}

Reading Attributes at Runtime

Use reflection to read attributes and act on them.

Type type = typeof(SampleClass);
var authors = type.GetCustomAttributes<AuthorAttribute>(inherit: false);

foreach (var author in authors)
{
    Console.WriteLine($"Class author: {author.Name}, version: {author.Version ?? "N/A"}");
}

MethodInfo? method = type.GetMethod("DoWork");
AuthorAttribute? methodAuthor = method?.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine($"Method author: {methodAuthor?.Name}");

Output:

Class author: Alice, version: 1.0
Class author: Bob, version: N/A
Method author: Charlie

AttributeUsage Explained

AttributeUsage controls how your attribute can be applied.

[AttributeUsage(
    AttributeTargets.Property | AttributeTargets.Field,
    AllowMultiple = false,
    Inherited = true
)]
public class DisplayNameAttribute : Attribute
{
    public string Name { get; }
    public DisplayNameAttribute(string name) => Name = name;
}
  • AttributeTargets: where the attribute can be applied (class, method, property, etc.)
  • AllowMultiple: whether the same attribute can appear multiple times
  • Inherited: whether derived classes inherit the attribute

Positional vs Named Parameters

Constructor parameters are positional; properties and fields are named.

public class ValidationAttribute : Attribute
{
    public int MinLength { get; }
    public int MaxLength { get; }
    public string? ErrorMessage { get; set; }

    public ValidationAttribute(int minLength, int maxLength)
    {
        MinLength = minLength;
        MaxLength = maxLength;
    }
}

[Validation(1, 100, ErrorMessage = "Value out of range")]
public string UserInput { get; set; } = "";

Common Patterns with Attributes

Attributes are widely used in ORMs, Serialization, and validation frameworks.

// JSON serialization attributes
public class Product
{
    [JsonPropertyName("product_id")]
    public int Id { get; set; }

    [JsonIgnore]
    public string? InternalCode { get; set; }

    [JsonPropertyOrder(1)]
    public string Name { get; set; } = "";
}

// Data validation
public class User
{
    [Required]
    [StringLength(100, MinimumLength = 3)]
    public string Username { get; set; } = "";

    [Range(18, 120)]
    public int Age { get; set; }

    [EmailAddress]
    public string? Email { get; set; }
}

Common Mistakes

  1. Not specifying AttributeUsage: Without it, your attribute defaults to all targets with AllowMultiple = false.

  2. Forgetting to inherit from Attribute: A class must inherit from System.Attribute to be used as an attribute. The compiler enforces this.

  3. Overusing attributes for business logic: Attributes are for metadata, not executable logic. Use them to annotate, not to implement behavior.

  4. Case sensitivity in named parameters: Named parameters must match the property name exactly. The compiler does not validate property names at compile time for attribute constructors.

  5. Not handling AllowMultiple correctly: If AllowMultiple = false, applying the attribute twice causes a compile error. Design carefully.

Practice Questions

  1. Create a [Documentation("description")] attribute and write a function that prints documentation for all methods in a class.

  2. Implement a [Deprecated("use instead")] attribute and write a code analyzer that lists all deprecated members.

  3. Use [CallerMemberName], [CallerFilePath], and [CallerLineNumber] to create a logging helper without manual parameter passing.

  4. Challenge: Build a mini-validation framework using custom attributes that validates string length, numeric ranges, and non-null values.

FAQ

Can attributes have constructors with optional parameters?

Yes, attributes can have optional parameters in their constructors. Named parameters (properties) can also be optional.

How do I make an attribute apply only to specific types?

Use AttributeTargets to restrict targets. For type-level restrictions, validate in the attribute's consumer at runtime.

Are attributes inherited by derived classes?

Yes, unless you set Inherited = false in AttributeUsage. Use GetCustomAttributes with inherit parameter to control this.

Can I create generic attributes?

No, generic attribute types are not allowed. You cannot write public class MyAttribute : Attribute.

How do I get attributes on method parameters or return values?

Use ParameterInfo.GetCustomAttributes for parameters and MethodInfo.ReturnParameter.GetCustomAttributes for return values.

Mini Project: Permission Checker

Build a permission-based access control system using custom attributes.

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class RequirePermissionAttribute : Attribute
{
    public string Permission { get; }
    public RequirePermissionAttribute(string permission) => Permission = permission;
}

public class DocumentService
{
    [RequirePermission("read")]
    public void ViewDocument(int id) =>
        Console.WriteLine($"Viewing document {id}");

    [RequirePermission("write")]
    [RequirePermission("delete")]
    public void DeleteDocument(int id) =>
        Console.WriteLine($"Deleting document {id}");
}

public class AccessController
{
    private readonly HashSet<string> _userPermissions;

    public AccessController(params string[] permissions)
    {
        _userPermissions = new HashSet<string>(permissions);
    }

    public bool CanExecute(MethodInfo method)
    {
        var required = method.GetCustomAttributes<RequirePermissionAttribute>();
        foreach (var attr in required)
        {
            if (!_userPermissions.Contains(attr.Permission))
                return false;
        }
        return true;
    }
}

// Usage
var controller = new AccessController("read", "write");
var service = new DocumentService();
MethodInfo viewMethod = typeof(DocumentService).GetMethod("ViewDocument")!;
MethodInfo deleteMethod = typeof(DocumentService).GetMethod("DeleteDocument")!;

Console.WriteLine($"Can view: {controller.CanExecute(viewMethod)}");
Console.WriteLine($"Can delete: {controller.CanExecute(deleteMethod)}");

Output:

Can view: True
Can delete: False

Attributes in C# provide a clean, declarative way to add metadata to your code. Combined with reflection, they enable frameworks and tools to make intelligent decisions about your code at runtime without coupling to your business logic. The .NET ecosystem uses attributes everywhere, from ASP.NET controllers to Entity Framework mappings.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro