Using Dependency Injection for Implementation Enumeration

...There is probably a better name for this

Scenario

I'm building a system that will look at a lot of transaction data and determine if each transaction qualifies for one of many criteria. At a high level, I'm asking "Does this transaction qualify for any or all of sales criteria A, B, C,...,N?"

This entry will examine a poor approach without dependency injection, then an approach that will leverage Autofac to register all criteria with one entry.

Bad Approach

I could have a method that simply iterates though a series of functions:

This approach sucks. It's easy to see what we're doing, but every time a transaction type is added, we have to add it to the list. Additionally, all of the logic lives in one place, so it quickly becomes a mess when we've got numerous criteria and forget about unit testing a specific requirement.

Better Solution

Hey, what about Dependency Injection? I've been using Autofac for awhile, certainly there must be something for this!

Dependencies of an enumerable type provide multiple implementations of the same service (interface). This is helpful in cases like message handlers, where a message comes in and more than one handler is registered to process the message.

Hey! That's exactly what I want to do. I want to allow for multiple implementations of the same interface to describe what a sale is. So I create an interface for checking the transaction and returning a sale where appropriate.

This entry may look daunting at first, but it's pretty straightforward. The first line uses reflection to find all of the types in the same assembly as 'CriteriaASaleHandler'. The second line limits these types to only those ending with the name 'SaleHandler'. There are several ways to specify the correct types rather than name, but as a person preference, I stick with the naming convention. Finally, the last line tells Autofac to inject that type as whatever interface it inherits from.

Here is the best part. Autofac will return an Enumerable of objects for injection when the types were injected with 'RegisterAssemblyTypes' which makes for ridiculously easy injection from here on out.

Stay on Target!

Almost there. The final key to this is to properly inject the enumerated classes into your implementation. That means my final class that processes the multiple implementations will look something like this:

Autofac will then enumerate all of the implementations and return all of the Sales objects returned therein.

Conclusion

I've shown how to implement a dependency injection solution for testing an object against multiple criteria, giving better adherence to separation of concerns and test driven development strategies, while also giving the added benefit of adding handlers without the need to register each implementation with Autofac or changing the class that calls the enumeration of implementations.

Edit

Originally, I had each handler return a Sale object. I later realized it would be better to just have the handler do whatever it needs to do (in this case write any results to the database). Loren Paulsen arrived at the same conclusion independantly.