I'm trying to figure out if there's a better way to structure some code. Although it currently works, it always gets at me due to the complexity and crazy nature that it feels to have with generics constraints. I'd be interested to know if anyone has an idea for a neater solution.
I've included a class diagram to make things a little easier.
This is all going within a library, and I wanted to try and keep all my type safety where I can. The library has 3 layers of increasing complexity. Which I'll explain in a moment.
I'm using Generics to make all the types work. For example a Route is actually a List<T>
where T
is a Visit. Now because I've got the 3 layers, I want to be able to access properties on these Visits (and the Nodes that they correspond to) from the Route itself (and to make it easier to consume). So that actually makes a Route<Visit<Node>>
. Once you add that to a Solution which needs to be strongly typed Solution<Route<Visit<Node>>>
things get complicated.
This results in some kinda unslightly code:
public abstract class Solution<TSolution, TRoute, TVisit, TNode, TResource>
where TSolution : Solution<TSolution, TRoute, TVisit, TNode, TResource>, new()
where TRoute : Route<TRoute, TVisit, TNode, TResource>, new()
where TVisit : Visit<TVisit, TNode>, new()
where TNode : Element<TNode>
where TResource : Resource<TResource>
It all works nicely, but I have to define these constraints at each class/level. At each level of complexity I create some simple consumable class such as the following, essentially hiding the generic constraints which would make it impossible to consume.
Level1.Solution : Common.Solution<Solution, Route, Visit, Node, Resource>
They have also been made recursive based on advice from this question to allow me to extend the class. For example a Level2.Solution will needs to be able to specify a Level2.Route as one of the constraints, normally this won't work (co/contra variance and generics) without the recursion.
All in all, it works, but is a bit cringy to say the least. Anyone have any ideas how this can be re-worked nicely?