How to Get all classes with a custom attribute in C#
By FoxLearn 3/12/2025 3:31:34 AM 15
using System.Reflection; var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsDefined(typeof(ServiceAttribute)));
This code searches for classes in the current assembly that have the [Service]
attribute.
[Service] public class EmailService : IEmailService { public void SendEmail(string to, string subject, string body) { // Send email logic here } }
This can be useful in scenarios like auto-discovery of service classes during application startup or for implementing dependency injection.
In this article, we'll also cover searching across all loaded assemblies, handling inherited custom attributes, and retrieving the values of custom attributes.
Search Across All Loaded Assemblies
To search through all loaded assemblies, use AppDomain.CurrentDomain.GetAssemblies()
to retrieve all the currently loaded assemblies. Then, loop through each assembly and use GetType()
and IsDefined()
to find classes with the specified custom attribute.
var types = from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() where type.IsDefined(typeof(ServiceAttribute)) select type;
Alternatively, using method syntax, you could do:
AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes().Where(t => t.IsDefined(typeof(ServiceAttribute))));
If you want to search in assemblies that haven’t been loaded yet, you can opt for the MetadataReader
approach.
Handle Inherited Custom Attributes
Custom attributes can be inherited.
[Service] public abstract class ServiceBase { public abstract void ExecuteService(); } public class EmailService : ServiceBase { public override void ExecuteService() { // Implement service execution logic here } }
The [Service]
attribute is defined on the ServiceBase
class, and is inherited by EmailService
. Searching for classes with the [Service]
attribute would return both ServiceBase
and EmailService
by default. However, you might want to filter this to only get the derived classes, not the base class.
Filter Out Abstract Classes
You typically wouldn’t want abstract classes to appear in the search results. You can filter them out by checking the Type.IsAbstract
property:
assembly.GetTypes().Where(t => t.IsDefined(typeof(ServiceAttribute)) && !t.IsAbstract)
This would return only EmailService
, excluding the ServiceBase
abstract class.
Filter Out Classes That Inherited the Custom Attribute
By default, IsDefined(customAttributeType)
will return true
even if the attribute is inherited. If you want to avoid returning classes that inherit the attribute but don’t define it themselves, use the inherit
parameter:
assembly.GetTypes().Where(t => t.IsDefined(typeof(ServiceAttribute), inherit: false))
In this case, if EmailService
only inherited the [Service]
attribute from ServiceBase
, it would be excluded from the results.
Getting Custom Attribute Values
When a custom attribute contains values, you may want to extract those values.
For example, consider this Service
attribute with a value for the service type:
[Service("Email")] public class EmailService : IEmailService { // Email service logic }
To retrieve the custom attribute values, use GetCustomAttribute<T>()
to get the attribute object:
var assembly = Assembly.GetExecutingAssembly(); foreach (var type in assembly.GetTypes()) { var serviceAttribute = type.GetCustomAttribute<ServiceAttribute>(); if (serviceAttribute != null) { Console.WriteLine($"Service={type.Name} Type={serviceAttribute.ServiceType}"); } }
If the custom attribute isn’t defined on the type, GetCustomAttribute
will return null
. Otherwise, it returns the custom attribute object, and you can access its properties. For the above code, this would output:
Service=EmailService Type=Email
This allows you to work with the values specified in the custom attribute, providing more detailed information for your application logic.
- Global exception event handlers in C#
- How to Add or overwrite a value in ConcurrentDictionary in C#
- Handling Posted Form Data in an API Controller
- How to Add a custom action filter in ASP.NET Core
- How to Map query results to multiple objects with Dapper in C#
- How to Update appsettings.json in C#
- Injecting ILogger into Dapper Polly Retry Policy in C#
- Properly Disposing HttpContent When Using HttpClient in C#