通过反射使用泛型参数调用问题的方法

时间:2019-06-18 15:55:06

标签: c# generics

所以这是简化的类:

// 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) {}        
}

通常我可以很容易地一个接一个地打电话给他们,但是由于上课的数量超过了3,000个,我不想让这个电话成为通用的电话。我所取得的成就如下:

// 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 });

train方法使我抛出类型异常

  

类型'System.Collections.Generic.List'1 [ConsoleApp2334.TrainingClass]'的对象不能转换为类型'System.Collections.Generic.List`1

我也尝试像这样对Train方法进行泛型调用,并收到一条错误消息,指出它不是泛型

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

,错误是

  

Train(System.Collections.Generic.List`1 [ConsoleApp2334.Blank])不是GenericMethodDefinition。只能在MethodBase.IsGenericMethodDefinition为true的方法上调用MakeGenericMethod。

因此,在第一个王牌中,它抱怨错误的通用参数,在第二个王牌中,它抱怨不通用或不“定义”为一个通用参数。我在做什么错了?

1 个答案:

答案 0 :(得分:2)

您已经创建了RegModel<Blank>,并尝试使用Train来调用List<TrainingClass>。这将不起作用,因为在Train上调用的RegModel<Blank>仅接受List<Blank>

您需要一种将List<TrainingClass>转换为List<Blank>的方法。或更一般而言,给定TypeList<TrainingClass>,将列表转换为该Type的列表。一种方法是使用此方法:

// 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;
}

您可以调用此方法将datas转换为所需的类型,然后再将其传递给Train