Is it possible to simplify nested generics in C #?

I like generics in C #, but sometimes working with them can get a little complicated. Below I run into a problem. Is there any way to simplify this scenario? I donโ€™t see how, but I hope someone can :)

Given the three base classes:

public abstract class Inner { } public abstract class Outer<T> where T : Inner { } public abstract class Handler<TOuter, TInner> where TOuter : Outer<TInner> where TInner : Inner { public abstract void SetValue(TInner value); } 

And some simple implementations:

 public class In : Inner { } public class Out : Outer<In> { } public class HandleOut : Handler<Out, In> { public override void SetValue(In value) { } } 

Now my question is: for HandleOut type is set to "Out", so is there a way to simplify the definition of HandleOut with something like the public class HandleOut : Handler<Out> and still be possible to use the internal type as the SetValue parameter?

This is a very simple example, but sometimes I get a long list of common types in definitions, when usually all of them can be inferred from the first type. Are there any tricks I miss?

+6
source share
1 answer

No.

Although this conclusion is probably possible, it is not part of the language. You might be interested to suggest this to Roslyn (discover a new issue). Of course, this type of typical constraint may run into a problem in difficult cases, but, at least for simple ones, this is doable ... after all, where should the C # team put their time and effort into it?

Link Why common restrictions are not inherited , Damien_The_Unbeliever for comments .


In any case, in the code that you presented, although it is true that Out already gives you the type In , the general parameter TOuter not needed.

The following code works equally well:

 public abstract class Inner { } public abstract class Outer<T> where T : Inner { } public abstract class Handler<TInner> // NOTE: TOuter removed where TInner : Inner { public abstract void SetValue(TInner value); } public class In : Inner { } public class Out : Outer<In> { } public class HandleOut : Handler<In> // NOTE: Out removed { public override void SetValue(In value) { } } 

So, you can use Outer<TInner> instead of TOuter if you need it. Of course, if you keep the TOuter list, it will be less restrictive, as it will allow any derived type of Outer<TInner> instead of any derived type of TOuter .

Since you did not add โ€œnewโ€ to the general constraint, you are not creating objects of this type, but if this case comes, you can accept Func<Outer<TInner>> in the constructor.

+1
source

All Articles