0

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 ?

3
  • Right, Train(List<T> x) is not a generic method. It's a member of a generic type (whence the type parameter for that List), but it doesn't have its own type parameter. You need to provide a type parameter for the type. Commented Jun 18, 2019 at 15:58
  • @EdPlunkett Thanks, that clear off my confusion on the error messages themselves. That make sense.
    – Franck
    Commented Jun 18, 2019 at 16:00
  • It'd definitely throw an exception; how do you expect to pass an object of type List<TrainingClass> as a parameter of type List<Blank>! List<Blank> is the type of your parameter given your constructed type if you haven't noticed. Commented Jun 18, 2019 at 16:48

1 Answer 1

2

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.

7
  • I can't instantiate the class as TrainingClass The reason is that the library that uses that only read the properties of the TrainingClass class and not Blank class if we do that. But if i pass an object of type Blank it does see all the properties.
    – Franck
    Commented Jun 18, 2019 at 16:10
  • What is this library that you are using? How are you using it? What does it do? How are Blank and TrainingClass related? @Franck
    – Sweeper
    Commented Jun 18, 2019 at 16:12
  • Blank is one of the couple thousands of class i have. TrainingClass is the main class that contain the common property. The Library is ML.NET, microsoft machine learning. They have a method where you pass an object with properties to train the model. It only read the property of the type of object you pass. If you create the Blank object it only see the property height and width. if you pass a new Blank() as TrainingClass it only see NetSurface
    – Franck
    Commented Jun 18, 2019 at 16:15
  • 1
    @Franck Then datas has to be of List<Blank> as well, wouldn't it?
    – Sweeper
    Commented Jun 18, 2019 at 16:19
  • yes certainly. But i won't copy paste 3000 times this code for every class i need. If you know how to convert a collection to another type without the actual class as written that would be perfect. aka i can't do var newList = Data.Cast<Blank>(). That would mean i need to copy paste the code for every combinaison of classes.
    – Franck
    Commented Jun 18, 2019 at 16:27

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.