I have an interface ISnack
which when implemented by a class, it should have a default parameterless constructor. Basically this:
public interface ISnack<T> where T : new()
{
}
I use <T> where T : new()
just to enforce the parameterless constructor.
I would then implement the interface this way:
public class Cutlet : ISnack<Cutlet>
{
}
This works and it simply ensures Cutlet
class has a parameterless constructor.
Now I have an abstract base class Kitchen
:
public abstract class Kitchen<T> where T : ISnack
{
}
The requirement is that Kitchen
should have constraint where T
should be an ISnack
. But this wont work because there exists no ISnack
, but only ISnack<T>
.
If I tried this
public abstract class Kitchen<T> where T : ISnack<T>
{
}
it wouldn't 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 wouldn't make sense in my context.
If I could force ISnack
s to have a parameterless constructor without constraining by a T
type parameter, then T
in Kitchen<T>
could easily be an ISnack
. How to go about it?
A constructor that takes no parameters is called a parameterless constructor. Parameterless constructors are invoked whenever an object is instantiated by using the new operator and no arguments are provided to new .
Multiple interface constraints can be specified. The constraining interface can also be generic.
Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.
In c#, constraints are used to restrict generics to accept only the particular type of placeholders. By using where keyword, we can apply constraints on generics. In c#, you can apply multiple constraints on generic classes or methods based on your requirements.
You can't unless you add the constraint; generic constraints are cumulative, so to make the compiler happy you would have to have:
public abstract class Kitchen<T> where T : ISnack<T>, new()
If that is fine, then do that. If it isn't fine, then you'll have to remove the : new
from the original, and make do without it. This isn't as bad as it sounds, but it means you push validation down to execution rather than compilation. But: Activator.CreateInstance<T>()
still does what you would need, anyway - even without the new()
constraint. So you can replace:
T newObj = new T(); // validated by the compiler
with:
T newObj = Activator.CreateInstance<T>(); // not validated until executed
A handy trick when removing constraints can be: add a unit/integration test that finds the candidate types via reflection, and validate the missing constraint as part of your test suite.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With