views:

1008

answers:

21

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...

A: 

I don't think so.

You also can't use an abstract class for this.

Vaibhav
A: 

why do you need the types to have a parameterless constructor?

Because I iterate through the types and create instances of them using the Activator class, which requires it

Juan Manuel
+21  A: 

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.

Brad Wilson
A: 

@Brad: Yes and no, 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...

Juan Manuel
+6  A: 

You can't require a parameterless constructor, but you can require a method (static?) that returns a new instance of the object as the desired interface. Rather than writing all kinds of sophisticated object registries, you can just require a 'Create' method which handles the object-specific activation and hands you back a new IYourInterface. Like the factory pattern without requiring a separate factory.

Mike Haboustak
+5  A: 

Juan,

Unfortunately there is no way to get around this in a strongly typed language. You won't be able to ensure at compile time that the classes will be able to be instantiated by your Activator-based code.

(ed: removed an erroneous alternative solution)

The reason is that, unfortunately, it's not possible to use interfaces, abstract classes, or virtual methods in combination with either constructors or static methods. The short reason is that the former contain no explicit type information, and the latter require explicit type information.

Constructors and static methods must have explicit (right there in the code) type information available at the time of the call. This is required because there is no instance of the class involved which can be queried by the runtime to obtain the underlying type, which the runtime needs to determine which actual concrete method to call.

The entire point of an interface, abstract class, or virtual method is to be able to make a function call without explicit type information, and this is enabled by the fact that there is an instance being referenced, which has "hidden" type information not directly available to the calling code. So these two mechanisms are quite simply mutually exclusive. They can't be used together because when you mix them, you end up with no concrete type information at all anywhere, which means the runtime has no idea where to find the function you're asking it to call.

Chris Ammerman
A: 

I would like to remind everyone that:

  1. Writing attributes in .NET is easy
  2. Writing static analysis tools in .NET that ensure conformance with company standards is easy

Writing a tool to grab all concrete classes that implement a certain interface/have an attribute and verifying that it has a parameterless constructor takes about 5 mins of coding effort. You add it to your post-build step and now you have a framework for whatever other static analyses you need to perform.

The language, the compiler, the IDE, your brain - they're all tools. Use them!

Frank Krueger
+5  A: 

You can use type parameter constraint

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

class Test: ITest<Test>
{
    //...
}
aku
A: 

No you can't do that. Maybe for your situation a factory interface would be helpful? Something like:

interface FooFactory {
    Foo createInstance();
}

For every implementation of Foo you create an instance of FooFactory that knows how to create it.

landon9720
A: 

You do not need a parameterless constructor for the Activator to instantiate your class. You can have a parameterized constructor and pass all the parameters from the Activator. Check out MSDN on this.

Andrei Rinea
+1  A: 

@Mike Haboustak says:

you can require a method (static?) that returns a new instance of the object as the desired interface. Rather than writing all kinds of sophisticated object registries, you can just require a 'Create' method

You can certainly have an instance method to do this. Not a static method. Interfaces cannot have static methods on them. Nor can a static method be marked abstract.

Furthermore, if the Create method you mention is an instance method, you pretty much need to have a registry mechanism of some sort. Because if the Create method is an instance method then Juan's instantiator process must have access to an existing instance of the class on which to call the method. Which means that the caller would have had to give one to Juan's process ahead of time at some point... Which is unfortunately pretty much the definition of a registry mechanism.

And just to be clear, a registry is also by definition going to be a run-time mechanism, so Juan will still not get his compile-time security that way.

Chris Ammerman
A: 

@Turbulent Intellect, What you say kinda makes sense to me; but, is that really the reason? I don't need explicit type information, just to require that the type implements a specific constructor (I see it as the same as to require a specific method, part of the contract).

I don't believe it's so crazy a requirement for it not to exist...

@aku, I thought about that, however, I don't need the class to be generic, so that's an overhead in the design I don't like

Juan Manuel
+1  A: 

Juan Manuel said:

I don't need explicit type information, just to require that the type implements a specific constructor

The problem isn't that you don't have explicit type information, because you do: either in the Type object, or the String class name that you pass to Activator.CreateInstance.

My discussion of explicit type information was relating to the reason why you can't have a constructor as part of an interface. A constructor is not just like another method. It is special. It is by definition tied to specific class.

I'll reiterate that the entire point of an interface (and abstract classes, and virtual methods) is to handle an object without the caller needing to know what type it is, because the instance knows itself what type it is. But before you call the constructor, there is no instance, so the type information isn't there yet.

And because this is the way an interface works, it means the runtime can't know what class to instantiate from the interface alone.

Chris Ammerman
+1  A: 

Juan Manuel said:

@aku, I thought about that, however, I don't need the class to be generic, so that's an overhead in the design I don't like

I think you should give aku's suggestion another look. I'm not an expert on reflection.... If you can make your instantiation method generic, you can handle ITest for any type argument T, and guarantee at compile time that any T implements a parameterless constructor.

If you can do that, he has proved me wrong.

You may not need the generic for any other reason, but it may be the only way you'll get your compile-time guarantee.

Chris Ammerman
A: 

That can be done (that's one of the reasons I don't understand why it cannot be a part of the contract in the interface)... but as I said, I don't like it...

Juan Manuel
+5  A: 

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() { }
}
Chris Ammerman
A: 

Well, thanks for all the answers, I really enjoyed the debate but we kinda diverted from the original question.

I see there's no way to achieve what I need, I'll add a runtime check and document it for the other developers.

Thanks again!

Juan Manuel
+1  A: 

Call a RegisterType method with the type, and constrain it using generics. Then, instead of walking assemblies to find ITest implementors, just store them and create from there.

void RegisterType<T>() where T:ITest, new() {
}
Mark Brackett
A: 

I see there's no way to achieve what I need

I'm still not seeing a compelling basis for support for what you need. It doesn't seem to be a coherent, because to call a constructor you have to know the concrete type anyway.

DrPizza
+2  A: 

So you need a thing that can create instances of an unknown type that implements an interface. You've got basically three options: a factory object, a Type object, or a delegate. Here's the givens:

public interface IInterface
{
    void DoSomething();
}

public class Foo : IInterface
{
    public void DoSomething() { /* whatever */ }
}

Using Type is pretty ugly, but makes sense in some scenarios:

public IInterface CreateUsingType(Type thingThatCreates)
{
    ConstructorInfo constructor = thingThatCreates.GetConstructor(Type.EmptyTypes);
    return (IInterface)constructor.Invoke(new object[0]);
}

public void Test()
{
    IInterface thing = CreateUsingType(typeof(Foo));
}

The biggest problem with it, is that at compile time, you have no guarantee that Foo actually has a default constructor. Also, reflection is a bit slow if this happens to be performance critical code.

The most common solution is to use a factory:

public interface IFactory
{
    IInterface Create();
}

public class Factory<T> where T : IInterface, new()
{
    public IInterface Create() { return new T(); }
}

public IInterface CreateUsingFactory(IFactory factory)
{
    return factory.Create();
}

public void Test()
{
    IInterface thing = CreateUsingFactory(new Factory<Foo>());
}

In the above, IFactory is what really matters. Factory is just a convenience class for classes that do provide a default constructor. This is the simplest and often best solution.

The third currently-uncommon-but-likely-to-become-more-common solution is using a delegate:

public IInterface CreateUsingDelegate(Func<IInterface> createCallback)
{
    return createCallback();
}

public void Test()
{
    IInterface thing = CreateUsingDelegate(() => new Foo());
}

The advantage here is that the code is short and simple, can work with any method of construction, and (with closures) lets you easily pass along additional data needed to construct the objects.

munificent
A: 

How do you find the types in the first place?

Hallgrim