Generics are a genuinely useful and powerful tool in .Net. Sometimes developers see part of the potential but not the whole story. This was the case in a recent Pull Request I reviewed.
The Pull Request in question related to some cleaning up that a developer had undertaken within our user management pages. These are standard lists of different types of user which can be filtered, exported to excel etc. The original developer of these pages had done a great Ctrl-C, Crtl-V for the first 2 different types. The developer of the Pull Request I was reviewing had set about to clean this up and used generics to do so. So far so good. The problem came when I noticed a raft of switch statements throughout two of the methods in the revised service. For example:
When I see a switch statement like this I have two clear thoughts. One, this does not allow for easy further extension or modification and two, there is actually just one line of code that needs executing on different models so lets write the code to do that.
This is a nice solution that allows for further IUserManagementModel based objects to be exported to Excel without this code needing to change. This is a real world example of Bertrand Meyer’s Open/Closed principle that I mentioned in my last post.
As I continued the review I came across the issue further as shown in the GetUsersQuery() method show below:
Once again the multiple switch statements were replicating code on objects that were all based on IUserManagementModel. It seemed obvious that the UserType and query values could actually be returned from the models. So that’s what we did:
This was achieved by modifying the IUserManagementModel interface:
(The ApplySort() method follows the same approach as GetModelQueryFor() to remove other code in the class that started off with a switch statement handling sorting the query result).
By the time we’d finished pairing up, the developer and myself were happy with the results. We’d removed the switch statements and realised more of the power of generics. That power is released by ensuring that you push all data and behaviour down to your abstractions. That way, your generic code can be written to interact with the abstracted type and not the instance of the objects.
If you’d like to discuss any of my thoughts here then as always please contact me via twitter or email.