Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to enforce parameterless constructor without generic constraint

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 ISnacks 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?

like image 519
nawfal Avatar asked Oct 09 '12 11:10

nawfal


People also ask

How do you call a parameterless constructor?

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 .

Can a generic class have multiple constraints?

Multiple interface constraints can be specified. The constraining interface can also be generic.

What does the generic constraint of type interface do?

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.

How do I restrict a generic class in C#?

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.


1 Answers

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.

like image 200
Marc Gravell Avatar answered Oct 26 '22 23:10

Marc Gravell