Skip to content

Get All C# Classes Implementing an Interface

Reading Mode

There may be instances in software applications, whereby there is a requirement to get a list of classes in an application that implement a specific interface and do something with them.

In my instance, I needed to retrieve a list of Entity Classes. In the application, all Domain Entity classes implement a common interface of IDomainEntity.

Although initially it may seem a little heavy handed to enforce your POCO classes to inherit and implement an interface, there are also some good reasons to do this.

In this post, I will provide an example of how to use reflection to retrieve a list of classes that implement a specific interface and then execute a method on that interface.

Commonality of data

In most applications you may require some commonality of data, for instance, every Attribute may require a Name, Description, Added Date, Modified Date or even if it is visible in certain sections of your of application code. Although these names my be different in your data layer i.e. they map to different field names in your database, you may want to have consistency in your application layer.

In some instances, you may just want to add an Empty Marker Interface to provides a mechanism associate metadata with a class where the language does not have explicit support for such metadata, or you need to ensure that a classes implement a specific method

A side benefits of this type of approach, is that it provides a mechanism for developers to identify the purpose of a class during development. For Instance, if you notice that a class implements the IDomainEntity interface, you can immediately identify that the class is a domain entity and from there will be able to deduce which layer it is implemented in, without having to search all references etc. In some large code bases this approach my help to reduce complexity and cognitive load.

These practices my typically be defined within an organisations Coding Conventions, for particular products or environments. In may on the outset seem heavy handed or even wasteful but on occassion it can help to eliminate ambiguity of POCO (Plain Old C# Classes) classes throughout an application stack.

The .net framework does provide support for Custom Attributes on classes, so you may want to consider this approach if you don't want to be bogged down by marker interfaces. Using Custom Attributes is beyond the scope of this article, but they are equally helpful and alternative solution to the one described in this post.

Sample Scenario

In trying to come up with a problem domain, in which to use this type of solution, I came up with a scenario in which you may need to store Reference Entities within a Redis Cache store. You may need to store Session Time Outs on your Redis keys, and these may be configured for couple of hours. You may have some kind of process whereby when the Key times out, the cache is refreshed and all is good with the world. This is a typical approach using Factory Method pattern

On occasion during the course of the day, we may wan to flush the cache and reload it. This may need occur during the deployment process of the application to production. Your Build or deployment scripts may be configured to call an API end point to clear specific or all Domain Reference Entity Caches.

There may be a requirement to build in flexibility to flush all entities without the need to pass in a managed list of items and just ask the application itself to determine the list of entities that require flushing. It is entirely possible that new entities may have been added during the course of development or even in the previous deployment, so creating a managed list will be difficult. So there may be need to create a list dynamically using reflection to to scan the binaries to get all references of classes which implement specific interface.

Power of reflection

It's in situation like these that the power of Reflection comes into play. C# and Reflection in the .net framework are powerful tools to have in your arsenal, to solve a scenario such as this.

In a nutshell, reflection is when managed code has the ability to read its own metadata to find out information about the Assemblies, Modules and Types, it is composed of. Using reflection, developers can create an instance of a type and bind that type to an existing object. They can also get the Type from an existing object and access its properties. Using Reflection you can inspect the contents of an assembly.

The classes in the System.Reflection namespace, together with System.Type, enable you to obtain information about loaded assemblies and the types defined within, such as class, interface & value types.

The Common Language Runtime (CLR) loader manages application domains, which constitute defined boundaries around objects that have the same application scope, including loading each assembly into the appropriate application domain and controlling the memory layout of the type hierarchy within each assembly.

Assemblies contain modules, modules contain types and types contain members. Reflection provides objects that encapsulate assemblies, modules and types.

You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object. You can then invoke the type's methods or access its fields and properties.

Reflection in C#

Having a broader understanding of the capabilities of Dynamic Programming in the .net framework is certainly advantageous to your software development career.

The System.Reflection namespace contains classes that allow you to obtain information about the application and to dynamically add types, values, and objects to the application.

You can compare Reflection in .net framework to C++RTTI (Runtime Type Information), except that it has far richer capabilities. a C# program that uses reflection, uses either the TypeOf operator or the GetType() method to get the object’s type.

In the code below, I basically wrote a method that returns a list of strings containing the names of all classes implementing the IDomainEntity interface.

 public List<string> GetAllEntities()
 {
   return AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
         .Where(x => typeof(IDomainEntity).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
         .Select(x => x.Name).ToList();
 }

The AppDomain Represents an application domain, which is an isolated environment where applications execute. AppDomain instances are used to load and execute assemblies (Assembly).

The list above can then be used by our method to flush the entities.  We again use the power of reflection to retrieve a list of Common Data repositories defined in the Inversion Of Control container , in our case we're making use of Simple Injector  to return the corresponding common data repository with the flush cache interface implemented

private IPurge PurgeCache(string entity, string nameSpace)
{
    var instance = IocContainer.Instance
                .GetCurrentRegistrations().FirstOrDefault(s => s?.ServiceType?.Namespace != null
                && s.ServiceType.Namespace.Contains(nameSpace)
                && s.ServiceType.GenericTypeArguments.Any()
                && String.Equals(s.ServiceType.GenericTypeArguments[0].Name, entity, StringComparison.CurrentCultureIgnoreCase));
 
   return (IPurge)instance.GetInstance() ?? null;
 }

Reflection in .net

The base for reflection is the System.Type class, which is an abstract class representing a type in the Common Type System (CTS). The CTS class, enables the discovery of types used in a module and namespace and also determine if a given type is a reference or value type.

You can parse the metadata tables to search:

  • Fields
  • Properties
  • Fields
  • Events

In the examples above we used reflection to extract information from the application during runtime, and then to preform actions based on that data recieved.

Use cases for reflection

  • Get all global and non-global methods defined in an application.
  • Use MethodInfo to extract information such as parameters, name, return type, access modifiers and implementation details.
  • Use EventInfo to discover event-handler data type, the name, declaring type and custom attributes.
  • Use ConstructorInfo to get data on the parameters, access modifiers, and implementation details of a constructor.
  • Use Assembly to load modules listed in the assembly manifest.
  • Use PropertyInfo to get declaring type, reflected type, data type, name and writable status of a property or get and set property values.
  • Use CustomAttributeData to find information on custom attributes or review attributes without having to create instances.

Summary

The article above illustrates just how easy it is to use reflection to get information from your application regarding which classes implement specific interfaces.

It also illustrates how you can use reflection to determine which dependencies have been configured in your Inversion of Control (IOC) container.

Gary Woodfine
Latest posts by Gary Woodfine (see all)