Generic Type in Constructor

Generic Type in constructor

You can't make constructors generic, but you can use a generic static method instead:

public static Constructor CreateInstance<T>(int blah, IGenericType<T> instance)

and then do whatever you need to after the constructor, if required. Another alternative in some cases might be to introduce a non-generic interface which the generic interface extends.

EDIT: As per the comments...

If you want to save the argument into the newly created object, and you want to do so in a strongly typed way, then the type must be generic as well.

At that point the constructor problem goes away, but you may want to keep a static generic method anyway in a non-generic type: so you can take advantage of type inference:

public static class Foo
{
public static Foo<T> CreateInstance<T>(IGenericType<T> instance)
{
return new Foo<T>(instance);
}
}

public class Foo<T>
{
public Foo(IGenericType<T> instance)
{
// Whatever
}
}

...

IGenericType<string> x = new GenericType<string>();
Foo<string> noInference = new Foo<string>(x);
Foo<string> withInference = Foo.CreateInstance(x);

How to use constructor of Generic type

You'll need to take an explicit factory method. Type annotations only exist for compile-time purposes, and at runtime that T is just a TypeVar. Consider

class MyClass(Generic[T]):
def __init__(self, initialValue: Iterable[int], factory: Callable[[Iterable[int]], T]):
self.values: T = factory(initialValue)

Then call it as

test = MyClass([1, 2, 3], lambda x: tuple(x))

Note: It would be nice to just pass tuple as the second argument, but mypy seems to choke when converting that typename to a Callable. Other type checkers may be able to handle it; your mileage may vary.

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.

Calling constructor of generic type?

Generics are not reified at run-time. Since the information is not present, you have two solutions :

  • it can be stored at compile-time by introducing a private field with the class
  • you can use reflection to resolve generic types at runtime from an instance.

Here an example with a private field T and a constructor, by starting from your code :

public abstract class MyRepository<T extends DatabaseObject> {

private Class<T> type;

public MyRepository(Class<T> type) {
this.type = type;
}

public <T> List<T> getList() {
Cursor cursor = getCursor(null, null); // how to do this?
// excess code removed, rest of function not relevant to question
return null;
}

protected <T extends DatabaseObject> Cursor getCursor(String selection, String[] selectionArgs) {
DatabaseObject databaseObject = instantiateFromType(); // how to do this?
String tableName = databaseObject.getTableName();
String[] projection = databaseObject.getProjection();
String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER;
Cursor cursor = database.query(
tableName,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
return cursor;
}

private DatabaseObject instantiateFromType() {
try {
T interfaceType = (T) type.newInstance();
return interfaceType;
}
catch (Exception e) {
// TODO to handle
}
}
}

Here your DogRepository :

public class DogRepository extends MyRepository<Dog> {

public DogRepository() {
super(Dog.class);
}

}

with a Dog which implements DatabaseObject:

public class Dog implements DatabaseObject{
//todo
}

To answer to your comment.

The line DogRepository(Class type), is it necessary to pass in
the class as an argument?

Not is is not needed (sorry I bad read your comment)).

And to go further, as you may notice, constructors for concrete repositories are boiler plate code.

If you use reflection to resolve the class behind the generic used in DogRepository, you don't need to define a custom constructor any longer for it.

For example to retrieve the type used in the repository, Spring does the job with its own library using JDK reflection mechanisms with something like that :

Map<TypeVariable, Type> source = GenericTypeResolver.getTypeVariableMap(DogRepository.class);

Spring has its library because it uses much reflection.

But in your case, you can also do the job without using a lib but with your own utility class. Here a sample to resolve the generic type from a repository instance.

DogRepository dogRepository = new DogRepository();
Class<?> typeClass = (Class<?>) ((ParameterizedType) dogRepository.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println("typeClass=" + typeClass );

With reflection to resolve the effective generic type in MyRepository constructor :

public abstract class MyRepository<T extends DatabaseObject> {

private Class<T> type;

public MyRepository() {
type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
...
}

repository concrete classes don't need custom constructor any longer :

public class DogRepository extends MyRepository<Dog> {

}

Generic class with generic constructor?

You are correct. Generic constructors aren't supported.

You could probably try the following:

Create a lower level common interface

public interface IMyClass {
//...some common stuff
IMyClass Parent { get; set; }
}

And use that as the common link between the types

public class MyClass<T> : IMyClass {
public MyClass(IMyClass parent = null) {
Parent = parent;
}
public IMyClass Parent { get; set; }
// ... Additional stuff
}

How to call constructor of generic type in class constructor

There's no way to check if a class has a default constructor in compile time. I would solve this problem by passing a factory that creates instances of the given type:

class Matrix2D<T : Any> : Cloneable, Iterable<T> {
private val array: Array<Array<Any>>

constructor(rows: Int, columns: Int, default: T) :
this(rows, columns, { default })

constructor(rows: Int, columns: Int, factory: () -> T) {
when {
rows < 1 -> throw MatrixDimensionException("Number of rows should >= 1")
columns < 1 -> throw MatrixDimensionException("Number of columns should be >= 1")
}
array = Array(rows) { Array<Any>(columns) { factory() } }
}
}

Please notice that you cannot use an array of type T in this case because information about its actual type is erased at runtime. Just use an array of Any and cast instances to T where necessary.

How to pass a generic type object to a class constructor

There are multiple issues with your code, but to take the error you are concerned with here, DbContext is not a non-abstract type so you cannot use it with the new() generic constraint. It also does not implement IDbContextFactory. There's a couple of things you can do. First would be to make UOW generic and match the same generic constraints, like this:

class UOW<TContext> : IUOW
where TContext : DbContext, IDbContextFactory<TContext>, new()
{
public UOW(Repo<TContext> repo)
{
}
}

The second is to use a concrete class that does work with all of those constraints, for example:

class MyContext : DbContext, IDbContextFactory<MyContext>
{
public MyContext CreateDbContext()
{
throw new NotImplementedException();
}
}

class UOW : IUOW
{
public UOW(Repo<MyContext> repo)
// ^^^^^^^^^ Use the new object here
{
}
}

Can I use type as value (or correctly infer generic class type from constructor parameter)?

The problem is that you want to manually specify one type parameter and have the compiler infer the other one. That's called partial type argument inference and TypeScript doesn't have it (as of TS3.4). You can either manually specify all type parameters (which you don't want to do), or have all type parameters inferred by the compiler (which you can't do because there's nothing from which you can infer the specified type).

There are two main workarounds for this situation:

The first is to rely entirely on type inference and use a dummy parameter to infer the type you would normally specify. For example:

class GenericCLass<T, K extends keyof T> {
keyNameFromAnotherType: K;

// add dummy parameter
constructor(dummy: T, keyNameFromAnotherType: K) {
this.keyNameFromAnotherType = keyNameFromAnotherType;
}
}

const test = new GenericCLass(null! as InterfaceWithProperties, 'stringProperty');
// inferred as GenericCLass<InterfaceWithProperties, "stringProperty">

You can see that the value passed in as the first parameter is just null at runtime, and the constructor doesn't look at it at runtime anyway. But the type system has been told that is is of type InterfaceWithProperties, which is enough for the type to be inferred the way you want.

The other workaround is to break up anything that would normally use partial inference into two pieces via currying; the first generic function will let you specify one parameter, and it returns a generic function (or a generic constructor in this case) that infers the other parameter. For example

// unchanged
class GenericCLass<T, K extends keyof T> {
keyNameFromAnotherType: K;

constructor(keyNameFromAnotherType: K) {
this.keyNameFromAnotherType = keyNameFromAnotherType;
}
}

// curried helper function
const genericClassMaker =
<T>(): (new <K extends keyof T>(
keyNameFromAnotherType: K
) => GenericCLass<T, K>) =>
GenericCLass;

// specify the one param
const InterfaceWithPropertiesGenericClass =
genericClassMaker<InterfaceWithProperties>();

// infer the other param
const test = new InterfaceWithPropertiesGenericClass('stringProperty');
// inferred as GenericCLass<InterfaceWithProperties, "stringProperty">

That leaves your class definition alone but creates a new helper function which returns a partially specified version of the GenericClass constructor for you to use. You can do it in one shot but it's ugly:

const test = new (genericClassMaker<InterfaceWithProperties>())('stringProperty');
// inferred as GenericCLass<InterfaceWithProperties, "stringProperty">

Anyway, hope one of those works for you. Good luck!

Injecting primitive type in constructor of generic type using Microsoft DI

With MS.DI, it's impossible to construct an open-generic registration using a factory method, just as you did with the IService registration.

The solution here is to wrap all primitive constructor values into a Parameter Object, so the DI Container can resolve it as well. For instance:

// Parameter Object that wraps the primitive constructor arguments
public class GenericClassSettings
{
public readonly string ConnectionString;

public GenericClassSettings(string connectionString)
{
this.ConnectionString =
connectionString ?? throw new ArgumentNullExcpetion();
}
}

The GenericClass<T>'s constructor can now depend on the new Parameter Object:

public GenericClass(
GenericClassSettings settings,
IGenericClass2<T> anotherGenericInterface,
IInterface anotherInterface)
{
_connectionString = settings.ConnectionString;
_executer = anotherGenericInterface;
_sproc = anotherInterface;
}

This allows you to register both the new parameter object and the open-generic class:

host.Services.AddSingleton(new GenericClassSettings("my connection string"));

host.Services.AddSingleton(typeof(IGenericClass<>), typeof(GenericClass<>));


Related Topics



Leave a reply



Submit