More and more recently I’ve found myself running into situations where I need to add in seemingly redundant collections of generic constraints onto methods and classes, or have to add constraints for generic types I don’t even end up using.

For example, if I have INode<T> where T:struct and I want to have a IGraph that handles an abstract base class implementing INode (not the best design, but not the point), ideally I’d just have to type something like IGraph<T> where T:class,INode<_> but instead I seem to have to use IGraph<T,U> where T:class,INode<U> where U:struct. Not only including the U argument (which I didn’t plan to use) but also having to constrain U to a struct even though that constraint should have been implicit because that constraint was present in INode’s definition. While it’s not too big an issue in this example, I’ve had cases where I needed upwards of 6 unused generic arguments with their own rows of constraints that could have been implicitly determined, which gets very messy. Is there a feature that would get around these issues?

They cannot be implicitly determined. Consider the case where you (or someone) wants to implement IGraph<T> where T is Node<int> for example. The implementation would have no way of accessing the inner type of INode during compile time. Therefore, you must define IGraph<T,U> so that any implementing class also has access to U. If IGraph implementations should not need access to the inner type of INode, then it sounds like INode should have a super interface (eg. IBaseNode and then INode<T> : IBaseNode) which contains the non-type specific methods.

TL;DR: You should not be constraining to INode<T> if IGraph or implementing classes do not care about T. You are effectively trying to constrain the interface for no reason since the code does not depend on T.
I do think it could pretty clearly be implicitly determined (as in, the compiler fills in the blanks like var, not that it’s ignored), but the “super interface” thing you mention is just the thing I was looking for, thank you. Somehow I never thought of using interface inheritance in that way.
Can’t you design your IGraph<T> so that it uses INode directly? I.e.

That would work unless you wanted a specific implementation of the INode to be specified, thus the where T:class I stipulated for the purposes of this example.

source