Enumerating classes which implement a generic interface

Wow… exciting topic, eh?  It is actually somewhat interesting, though.

Background:
I’m working on a project where we’ve had to split validation away from the business entities for a couple reasons.  First of all, business entities live at a lower level than the logic classes responsible for loading and saving them.  They are kind of ignorant of their surroundings, and so not all validation rules can be expressed from there.  Instead, the validation rules are considered "business logic", and as such, they live in the "logic" assembly.  The problem is that we need validation to be kicked off by Linq attempting to save the entities via the OnValidate method.

What we settled on was a ValidationManager class which lives in the Business assembly, but gets populated from the Logic assembly at runtime with a dictionary which is used to look up the proper validator for a given entity.  The IValidator<TEntity> interface is defined in the Business assembly, but any common assembly would do.  So the business entities know what a validator looks like without having to have a reference to the validators themselves.

The next hurdle, and the one responsible for this post’s title, is doing the registration.  At first, we just had a static constructor for the base logic class that had one line for each validator, associating it with the business entity it validates and pushing it into the dictionary.  This works just fine, but it turns out it’s pretty easy to forget to register a validator when a new type of entity is created.  You’ve got the entity, and you’ve got the validator, but unless you register them, nothing will actually happen during the OnValidate method.

Solution:
Instead of manually adding code to register each validator, I’m now using some reflection code to find all the classes which implement IValidator<T>, and register them automatically.  The code is short, and pretty sweet if I must say so myself.

    Type validatorType = typeof(IValidator<>);
    foreach (Type objType in Assembly.GetExecutingAssembly().GetTypes())
    {
        foreach (Type interfaceType in objType.GetInterfaces())
        {
            if (interfaceType.IsGenericType && (interfaceType.GetGenericTypeDefinition() == validatorType))
            {
                Type argType = interfaceType.GetGenericArguments()[0];
                ValidationManager.RegisterValidator(argType, objType);
            }
        }
    }

Now I never have to manually register another validator again.  This loop could be expanded to register other types of classes (such as workflow classes) as well by adding additional branches to the inner if block.

Advertisement
This entry was posted in Computers and Internet. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s