Is there a way to force the use of a gapless constructor without a general restriction

I have an ISnack interface, which, when implemented by a class, must have a constructor without parameters without parameters. Mainly:

 public interface ISnack<T> where T : new() { } 

I use <T> where T : new() to force the use of a constructor without parameters.

I would then implement the interface like this:

 public class Cutlet : ISnack<Cutlet> { } 

This works, and it just ensures that the Cutlet class has a parameterless constructor.

Now I have an abstract base class of Kitchen :

 public abstract class Kitchen<T> where T : ISnack { } 

The requirement is that Kitchen should have a restriction where T should be ISnack . But this does not work, because there is no ISnack , but only ISnack<T> .

If I tried this

 public abstract class Kitchen<T> where T : ISnack<T> { } 

it will not compile ( 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'ISnack<T>' ), and also does not make sense in my context.

If I could force ISnack have a dimensionless constructor without being limited to a parameter of type T , then T in Kitchen<T> could easily be ISnack . How to do it?

+6
source share
3 answers

You cannot, unless you add a restriction; general constraints are cumulative, so for the compiler to be happy you have to:

 public abstract class Kitchen<T> where T : ISnack<T>, new() 

If this is normal , then do it . If this is not the case, then you will have to remove : new from the original and do without it. This is not as bad as it sounds, but it means that you are pushing validation before execution, not compilation. But: Activator.CreateInstance<T>() still does what you need, in any case - even without the restriction of new() . So you can replace:

 T newObj = new T(); // validated by the compiler 

from:

 T newObj = Activator.CreateInstance<T>(); // not validated until executed 

A convenient trick when removing restrictions can be as follows: add a unit / integration test that finds candidate types through reflection, and check the missing restriction as part of your test suite.

+10
source

You can use the second general parameter:

 abstact class Kitchen<T, S> where T : ISnack<S> where S : new() .... 

This will solve your problem.

Adding a second parameter to the class can also lead to some problems that I have encountered since the advent of .NET 2.0. In some difficult situations, you may need to add more general parameters to the classes than you like. I usually break up the overall chain by adding more live broadcasts (e.g. (SpecificType)base.MyTypeTProperty ). Comment: I try to find a sample later

+3
source

just add the constraint to T again

 public abstract class Kitchen<T> where T : ISnack<T>, new() { } 
+1
source

Source: https://habr.com/ru/post/927243/


All Articles