Franck
Franck

Reputation: 4440

Problem calling method with generic parameter by reflection

So here are the simplified class :

// base class for all object
public class TrainingClass
{
    public double NetSurface { get; set; } = 0;
}

// one sample object
public class Blank : TrainingClass
{
    public double Height { get; set; } = 0;
    public double Width { get; set; } = 0;     
}

// the handling class
public class RegModel<T> where T : TrainingClass
{
    // empty constructor
    public RegModel() { }

    // 2 methods that use data of type T
    public void Train(List<T> datas) {}
    public void Solve(T data) {}        
}

Typically i can easily call them one by one but since the amount of class will go in excess of 3,000 i wanted t make the call generic. What i have achieved is the following :

// create the data type the generic need to be of
//(this is parameter in the real code)
Type dataType = typeof(Blank);

// create a dummy list of data (this is actually a property in the 
// class in the real code it's of TrainingClass type to allow for generic)
var datas = new List<TrainingClass>();

// create the generic base type
Type genericClass = typeof(RegModel<>);

// create the generic type
Type constructedClass = genericClass.MakeGenericType(dataType);

// create the class
var rm = Activator.CreateInstance(constructedClass);

// get the train method
var trainMethod = constructedClass.GetMethod("Train");

// invoke the train method passing the List<TrainingData>
trainMethod.Invoke(rm, new[] { datas });

the train method throw me a type exception

Object of type 'System.Collections.Generic.List'1[ConsoleApp2334.TrainingClass]' cannot be converted to type 'System.Collections.Generic.List`1

I also tried making a generic call for the Train method like so and get an error saying it's not generic

var trainMethodGeneric = trainMethod.MakeGenericMethod(typeof(Blank));

and the error is

Train(System.Collections.Generic.List`1[ConsoleApp2334.Blank]) is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.

So in the first ace it whine about wrong generic parameters and on the second one it whine about not being generic or not "define" as one. What am i doing wrong ?

Upvotes: 0

Views: 1532

Answers (1)

Sweeper
Sweeper

Reputation: 273850

You have created a RegModel<Blank>, and attempted to call Train with a List<TrainingClass>. This will not work because Train called on a RegModel<Blank> will only accept List<Blank>.

You need to have a way to convert a List<TrainingClass> to a List<Blank>. Or more generally, given a Type and a List<TrainingClass> convert the list to a list of that Type. One such way to do this is using this method:

// Note that although it says IList here, this method actually returns a List<T> at runtime
// We don't know the actual type of the list at compile time. The best we know
// is that it is some kind of a list.
static System.Collections.IList ConvertListToType<T>(Type type, List<T> list) {
    Type constructedListType = typeof(List<>).MakeGenericType(type);
    var newList = (System.Collections.IList)Activator.CreateInstance(constructedListType);
    list.ForEach(x => newList.Add(x));
    return newList;
}

You can call this method to convert datas to the required type before you pass it to Train.

Upvotes: 2

Related Questions