Attributes and Reflection
40 minAttributes provide metadata about code elements (classes, methods, properties), enabling you to add declarative information to your code. Attributes are stored in metadata and can be read at runtime. Attributes enable frameworks to understand and process your code. Understanding attributes enables framework integration. Attributes are essential for many .NET features.
Built-in attributes include [Obsolete] (marks code as deprecated), [Serializable] (enables serialization), [DllImport] (calls native code), [Conditional] (conditional compilation), and many more. These attributes provide instructions to the compiler and runtime. Understanding built-in attributes enables using framework features. Built-in attributes are widely used.
Reflection allows runtime inspection of types and members, enabling you to examine assemblies, types, methods, properties, and attributes at runtime. Reflection enables dynamic code execution, dependency injection, serialization, and ORM frameworks. Understanding reflection enables powerful runtime capabilities. Reflection is powerful but has performance costs.
Custom attributes can be created for specific purposes by inheriting from Attribute and using [AttributeUsage] to specify where they can be applied. Custom attributes enable domain-specific metadata. Attributes are read using reflection. Understanding custom attributes enables extensible designs. Custom attributes are used in many frameworks.
Reflection enables dynamic type creation, method invocation, and property access, but comes with performance overhead. Use reflection when necessary (frameworks, serialization) but avoid it in performance-critical paths. Understanding reflection trade-offs enables appropriate usage. Reflection is a powerful but expensive feature.
Best practices include using attributes for metadata, using reflection sparingly (it's slow), caching reflection results when possible, using built-in attributes when available, and documenting custom attributes. Understanding attributes and reflection enables framework integration and dynamic programming. Attributes and reflection are essential for many .NET features.
Key Concepts
- Attributes provide metadata about code elements.
- Built-in attributes: [Obsolete], [Serializable], [DllImport].
- Reflection allows runtime inspection of types and members.
- Custom attributes can be created for specific purposes.
- Reflection has performance overhead—use sparingly.
Learning Objectives
Master
- Using built-in attributes
- Creating custom attributes
- Using reflection to inspect types
- Understanding reflection performance implications
Develop
- Understanding metadata and reflection concepts
- Designing extensible frameworks
- Appreciating attributes' role in .NET
Tips
- Use attributes for declarative metadata.
- Use reflection sparingly—it has performance overhead.
- Cache reflection results when possible.
- Use built-in attributes when available.
Common Pitfalls
- Overusing reflection, causing performance issues.
- Not understanding attribute usage restrictions.
- Creating attributes that are too complex.
- Not caching reflection results, causing repeated overhead.
Summary
- Attributes provide metadata about code elements.
- Built-in attributes enable framework features.
- Reflection enables runtime type inspection.
- Custom attributes enable domain-specific metadata.
- Understanding attributes and reflection enables framework integration.
Exercise
Create custom attributes and use reflection to inspect types.
using System;
using System.Reflection;
// Custom attribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorAttribute : Attribute
{
public string Name { get; set; }
public string Version { get; set; }
public AuthorAttribute(string name, string version = "1.0")
{
Name = name;
Version = version;
}
}
// Class with custom attribute
[Author("John Doe", "2.0")]
public class Calculator
{
[Author("Jane Smith")]
public int Add(int a, int b)
{
return a + b;
}
public int Multiply(int a, int b)
{
return a * b;
}
}
class Program
{
static void Main(string[] args)
{
// Using reflection to inspect attributes
Type calculatorType = typeof(Calculator);
// Get class attributes
var classAttributes = calculatorType.GetCustomAttributes(typeof(AuthorAttribute), false);
foreach (AuthorAttribute attr in classAttributes)
{
Console.WriteLine($"Class author: {attr.Name}, Version: {attr.Version}");
}
// Get method attributes
var methods = calculatorType.GetMethods();
foreach (var method in methods)
{
var methodAttributes = method.GetCustomAttributes(typeof(AuthorAttribute), false);
foreach (AuthorAttribute attr in methodAttributes)
{
Console.WriteLine($"Method {method.Name} author: {attr.Name}");
}
}
// Create instance and call methods
var calculator = new Calculator();
var result = calculator.Add(5, 3);
Console.WriteLine($"Add result: {result}");
}
}