Is There a Generic Constructor with Parameter Constraint in C#

Is there a generic constructor with parameter constraint in C#?

As you've found, you can't do this.

As a workaround I normally supply a delegate that can create objects of type T:

public class A {

public static void Method<T> (T a, Func<float[,], T> creator) {
//...do something...
}

}

Generic constructor with new type constraint

To use new on a generic type, you would have to specify the new() constraint on your class/method definition:

public static E FromModel<T, E>(T other) 
where T : sysModel
where E : dbModel, new()

Since you are using a parameter in the constructor, you can't use new, but you can use the Activator instead and pass other as an argument:

public static E FromModel<T, E>(T other)
where T : sysModel
where E : dbModel
{
return (E)Activator.CreateInstance(typeof(E), new[]{other});
}

Specifying constructor constraint for Generic Parameter

Unfortunately, this isn't allowed in C#. You can have a new() constraint that forces the type to have a default constructor, but that is the only constructor related constraint supported by .NET.

Your best option is probably to define an interface you can use, and constrain to the interface. Instead of trying to set the object at construction, you can have an "Initialize" style method that takes the "A" object, and call that.

Is it possible to have a generic method with constraint of constructor with parameter?

No, you can't require a constructor with parameters. About the best you can do here would be to require a lambda:

public static List<T> ToObjectList<T>(this DataTable table,Func<DataRow,T> convert)
{
List<T> lst = new List<T>();

foreach (DataRow row in table.Rows)
lst.Add(convert(row));

return lst;
}

Usage:

var list = myDataTable.ToObjectList(dr=>new Person(dr));

Further reading:

Constraints on type parameters

Workaround for new() constraint with parameters in generics

Question

Again my primary question: Is this a possible/intelligent workaround to manage the new() constraint in generics with parameters?

Answer

Your passing a type(ClassX) and want to access an instance function(GenerateNew) without creating an instance -> well that's one problem you need to think about.
You can create a static factory(and\or use IOC) for creating new object's by types.

Question

Why do BaseClass and ClassX need to have a parameterless constructor while they won't be used in any case explicitly?

Answer

This constraint requires that the generic type that is used is non-abstract and that it has a default (parameterless) constructor allowing you to call it.
BTW, you are using the empty ctor by doing new T().

C#: Generic types that have a constructor?

It can be done with reflection:

public void CreateItem()
{
int constructorparm1 = 10;
T oItem = Activator.CreateInstance(typeof(T), constructorparm1) as T;
}

But there is no generic constraint to ensure that T implements the desired constructor, so I wouldn't advise doing this unless you are careful to declare that constructor in every type that implements the interface.

Passing arguments to C# generic new() of templated type

In order to create an instance of a generic type in a function you must constrain it with the "new" flag.

public static string GetAllItems<T>(...) where T : new()

However that will only work when you want to call the constructor which has no parameters. Not the case here. Instead you'll have to provide another parameter which allows for the creation of object based on parameters. The easiest is a function.

public static string GetAllItems<T>(..., Func<ListItem,T> del) {
...
List<T> tabListItems = new List<T>();
foreach (ListItem listItem in listCollection)
{
tabListItems.Add(del(listItem));
}
...
}

You can then call it like so

GetAllItems<Foo>(..., l => new Foo(l));

Initialize generic type with non-empty constructor

You can use reflection to invoke the constructor:

var constructorInfo = typeof(T).GetConstructor(new[] { typeof(int) });
if (constructorInfo != null)
{
object[] parameters = new object[] { index };
return (T)constructorInfo.Invoke(parameters);
}
else
{
// handle it
}

(adapted from https://stackoverflow.com/a/13523659/5962841)


Or, you can use activator to create an instance (see @datrax's answer)

(T)Activator.CreateInstance(typeof(T), index)

The feature you asked for has already often been requested.

The request for the feature is being tracked here (github csharp design repo), but don't expect it this year, it's not even prototyped or accepted.

How to constrain generic type to must have a construtor that takes certain parameters?

It's not possible. I'd like to see "static interfaces" to handle this, but don't expect them any time soon...

Alternatives:

  • Specify a delegate to act as a factory for T
  • Specify another interface to act as a factory for T
  • Specify an interface on T itself for initialization (and add a constraint so that T implements the interface)

The first two are really equivalent. Basically you'd change your proxy class to something like this:

public class GenericProxy<T>
where T: ClientBase, new()
{
string _configName;
T _proxy;
Func<string, T> _factory;

public GenericProxy(Func<string, T> factory, string configName)
{
_configName = configName;
_factory = factory;
RefreshProxy();
}

void RefreshProxy() // As an example; suppose we need to do this later too
{
_proxy = _factory(_configName);
}
}

(I assume you're going to want to create more instances later - otherwise you might as well pass an instance of T into the constructor.)



Related Topics



Leave a reply



Submit