Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you require a constructor with no parameters for types implementing an interface?

Is there a way?

I need all types that implement a specific interface to have a parameterless constructor, can it be done?

I am developing the base code for other developers in my company to use in a specific project.

There's a proccess which will create instances of types (in different threads) that perform certain tasks, and I need those types to follow a specific contract (ergo, the interface).

The interface will be internal to the assembly

If you have a suggestion for this scenario without interfaces, I'll gladly take it into consideration...

like image 676
juan Avatar asked Aug 25 '08 21:08

juan


3 Answers

Not to be too blunt, but you've misunderstood the purpose of interfaces.

An interface means that several people can implement it in their own classes, and then pass instances of those classes to other classes to be used. Creation creates an unnecessary strong coupling.

It sounds like you really need some kind of registration system, either to have people register instances of usable classes that implement the interface, or of factories that can create said items upon request.

like image 136
Brad Wilson Avatar answered Sep 28 '22 12:09

Brad Wilson


You can use type parameter constraint

interface ITest<T> where T: new()
{
    //...
}

class Test: ITest<Test>
{
    //...
}
like image 44
aku Avatar answered Sep 28 '22 12:09

aku


Juan Manuel said:

that's one of the reasons I don't understand why it cannot be a part of the contract in the interface

It's an indirect mechanism. The generic allows you to "cheat" and send type information along with the interface. The critical thing to remember here is that the constraint isn't on the interface that you are working with directly. It's not a constraint on the interface itself, but on some other type that will "ride along" on the interface. This is the best explanation I can offer, I'm afraid.

By way of illustration of this fact, I'll point out a hole that I have noticed in aku's code. It's possible to write a class that would compile fine but fail at runtime when you try to instantiate it:

public class Something : ITest<String>
{
  private Something() { }
}

Something derives from ITest<T>, but implements no parameterless constructor. It will compile fine, because String does implement a parameterless constructor. Again, the constraint is on T, and therefore String, rather than ITest or Something. Since the constraint on T is satisfied, this will compile. But it will fail at runtime.

To prevent some instances of this problem, you need to add another constraint to T, as below:

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

Note the new constraint: T : ITest<T>. This constraint specifies that what you pass into the argument parameter of ITest<T> must also derive from ITest<T>.

Even so this will not prevent all cases of the hole. The code below will compile fine, because A has a parameterless constructor. But since B's parameterless constructor is private, instantiating B with your process will fail at runtime.

public class A : ITest<A>
{
}

public class B : ITest<A>
{
  private B() { }
}
like image 33
Chris Ammerman Avatar answered Sep 28 '22 11:09

Chris Ammerman