Coder Perfect

Create a generic type instance with a parameter in the constructor?

Problem

Can I instantiate a piece of fruit in a generic method like this if BaseFruit includes a constructor that accepts an int weight?

public void AddFruit<T>()where T: BaseFruit{
    BaseFruit fruit = new T(weight); /*new Apple(150);*/
    fruit.Enlist(fruitManager);
}

Behind the comments, there is an example. It appears that the only way to accomplish this is to provide BaseFruit a parameterless constructor and then fill in the blanks using member variables. This is really impractical in my real code (not about fruit).

-Update- It appears that restrictions cannot be used to fix the problem in any way. There are three possible solutions based on the responses:

I believe reflection is the dirtiest, but I can’t decide between the other two.

Asked by Boris Callens

Solution #1

Also, here’s a simple example:

return (T)Activator.CreateInstance(typeof(T), new object[] { weight });

The new() constraint on T is just used to force the compiler to look for a public parameterless constructor at compilation time; the Activator class is the code that actually creates the type.

You’ll need to double-check that the specific constructor exists, and this type of requirement could be a code smell (or, at the very least, something you should aim to avoid in the current c# version).

Answered by meandmycode

Solution #2

There are no parameterized constructors available. If you have a “where T: new()” constraint, you can utilize a parameterless constructor.

It’s inconvenient, but that’s life:(

One of the issues I’d like to address with “static interfaces” is this one. Then you can confine T to just include static methods, operators, and constructors, and then call them.

Answered by Jon Skeet

Solution #3

Yes, modify your location:

where T:BaseFruit, new()

This, however, only works with constructors that have no parameters. You’ll need to find another way to establish your property (setting the property itself or something similar).

Answered by Adam Robinson

Solution #4

Activator is the most straightforward solution. CreateInstance()

Answered by user1471935

Solution #5

As Jon pointed out, restricting a non-parameterless constructor is a way of life. A manufacturing pattern, on the other hand, is a different solution. This is a simple constraint.

interface IFruitFactory<T> where T : BaseFruit {
  T Create(int weight);
}

public void AddFruit<T>( IFruitFactory<T> factory ) where T: BaseFruit {    
  BaseFruit fruit = factory.Create(weight); /*new Apple(150);*/    
  fruit.Enlist(fruitManager);
}

A functional approach is still another alternative. A factory method can be passed in.

public void AddFruit<T>(Func<int,T> factoryDel) where T : BaseFruit { 
  BaseFruit fruit = factoryDel(weight); /* new Apple(150); */
  fruit.Enlist(fruitManager);
}

Answered by JaredPar

Post is based on https://stackoverflow.com/questions/731452/create-instance-of-generic-type-whose-constructor-requires-a-parameter