Keywords: C# | Reflection | Attributes | PropertyInfo | GetCustomAttributes
Abstract: This article explores how to use reflection in C# to retrieve custom attribute information defined on class properties. By employing the PropertyInfo.GetCustomAttributes() method, developers can access all attributes on a property and extract their names and values. Using the Book class as an example, the article provides a complete code implementation, including iterating through properties, checking attribute types, and building a dictionary to store results. Additionally, it covers the lazy construction mechanism of attributes and practical application scenarios, offering deep insights into the power of reflection in metadata manipulation.
Introduction
In C# programming, reflection is a powerful mechanism that allows inspection and manipulation of type information at runtime. Custom attributes add metadata to code, and reflection enables access to this metadata. This article focuses on how to retrieve the names and values of custom attributes defined on class properties using reflection.
Core Concepts
Reflection is implemented through classes in the System.Reflection namespace, with PropertyInfo representing property information. The GetCustomAttributes() method returns an array of all attribute objects applied to a property. Attributes are constructed only when queried, supporting lazy initialization.
Implementation Steps
First, define a class with custom attributes, for example:
public class Book
{
[Author("AuthorName")]
public string Name { get; private set; }
}Use typeof(Book).GetProperties() to get all properties, iterate through each PropertyInfo, and call GetCustomAttributes(true) to obtain the attribute array. Filter specific attributes using type checks (e.g., the as operator), and extract property names and attribute values.
Complete Code Example
The following function returns a dictionary of property names and attribute values:
public static Dictionary<string, string> GetAuthors()
{
Dictionary<string, string> _dict = new Dictionary<string, string>();
PropertyInfo[] props = typeof(Book).GetProperties();
foreach (PropertyInfo prop in props)
{
object[] attrs = prop.GetCustomAttributes(true);
foreach (object attr in attrs)
{
AuthorAttribute authAttr = attr as AuthorAttribute;
if (authAttr != null)
{
string propName = prop.Name;
string auth = authAttr.Name;
_dict.Add(propName, auth);
}
}
}
return _dict;
}This code iterates through all properties of the Book class, checks if each attribute is of type AuthorAttribute, and if so, adds the property name and attribute value to the dictionary.
Supplementary Methods
For a single property, use GetProperty("Name").GetCustomAttributes(false).ToDictionary(a => a.GetType().Name, a => a) to build a dictionary directly. If only specific attribute values are needed, the GetCustomAttribute<T>() extension method is more efficient, e.g., var attr = typeof(Book).GetProperty("Name").GetCustomAttribute<DisplayAttribute>().
Attribute Construction Mechanism
Attributes in source code, such as [Author("P. Ackerman")], are equivalent to constructing an Author object at runtime. When GetCustomAttributes is called, the system initializes attribute instances, supporting multiple applications (e.g., with AllowMultiple = true).
Application Scenarios
This technique is widely used in serialization, validation, and documentation generation. For instance, in Web APIs, attributes define parameter constraints, and reflection automatically validates inputs; or in ORMs, properties are mapped to database columns.
Conclusion
Reflection provides a flexible way to access attribute metadata. By combining PropertyInfo and GetCustomAttributes, developers can efficiently extract attribute information from properties. Note that performance overhead should be considered, and caching results is advisable for frequent operations.