如何在C#中调用动态类型的Generic方法

时间:2014-01-27 17:36:45

标签: c# reflection types

我有以下代码:

public static List<object[]> Serialise2D_Rec<T>(IEnumerable<T> data)
{
    int numElts = 0;
    foreach (var item in data)
        numElts++;

    Type t = typeof(T); // Get type pointer
    PropertyInfo[] propList = t.GetProperties();


    List<object[]> toret = new List<object[]>();

    for (long propID = 0; propID < propList.Count(); ++propID)
    {
        var proptype = propList[propID].PropertyType;
        if (proptype.IsPrimitive || proptype == typeof(Decimal) || proptype == typeof(String))
        {
            toret.Add(new object[numElts + 1]);
            toret[toret.Count - 1][0] = propList[propID].Name;
            int row = 1;
            foreach (T item in data)
            {
                toret[toret.Count - 1][row] = propList[propID].GetValue(item, null);
                row++;
            }
        }
        else
        {
            var lst = (IList)Activator.CreateInstance((typeof(List<>).MakeGenericType(proptype)));
            foreach (T item in data)
            {
                lst.Add(propList[propID].GetValue(item, null));
            }
            List<object[]> serialisedProp = Serialise2D_Rec(lst);

        }
    }
    return toret;

}

然而,这一行将失败:

List<object[]> serialisedProp = Serialise2D_Rec(lst);

错误:

****: error CS0411: The type arguments for method '****.****.Serialise2D_Rec<T>(System.Collections.Generic.IEnumerable<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

如何在递归中指定类型,似乎动态泛型类型的语法并不是那么简单。

5 个答案:

答案 0 :(得分:4)

在您的案例中,我没有看到有效的泛型用例。泛型的使用假设您能够在编译时(或至少其祖先)静态识别类型。你为什么不接受非通用IEnumerable?如果您确实需要在data中提供一些基本类型的项目,请将其作为参数提供:

public static List<object[]> Serialise2D_Rec(IEnumerable data, Type t)
{
    …
    for (…)
    {
        if (…)
        {
        }
        else
        {
            …
            List<object[]> serialisedProp = Serialise2D_Rec(lst, proptype);
        }
    }
}

附注:使用扩展方法data.Count()代替foreach (var item in data) numElts++;

答案 1 :(得分:2)

由于您的类型是动态的,因此在运行时之前您不会知道泛型参数的类型。因此,您还必须将该函数视为动态函数,因为在运行时之前您不会知道函数通用签名的“类型”。

您必须使用反射动态调用泛型函数。见How do I use reflection to call a generic method?

答案 2 :(得分:1)

试试这个:

// Get The Method by reflection
    MethodInfo serializerInfo = typeof(Serializer).GetMethod("Serialise2D_Rec",
                        BindingFlags.Public | BindingFlags.Static); 

//Make a Generic instance of the type you want
    serializerInfo = serializerInfo.MakeGenericMethod(lst.GetType());

    List<object[]> serialisedProp = serializerInfo.Invoke(null, new object[] {lst});

而不是typeof()中的序列化程序放置了包含您的函数的类Serialise2D_Rec

答案 3 :(得分:1)

在这种情况下,您似乎不能使用泛型。该行失败,因为lst是非通用的IList,并且它作为对象传递给Serialise2D_Rec,这需要IEnumerable<T>

我建议你改变你的方法不是通用的;无论如何它都使用反射,它可能没有太大的影响。

试试这个:

public static List<object[]> Serialise2D_Rec(IList data)
{
    int numElts = 0;
    foreach (var item in data)
        numElts++;

    if (data.Count == 0)
        throw new Exception("Cannot handle empty lists.");

    Type t = data[0].GetType(); // Get type pointer
    PropertyInfo[] propList = t.GetProperties();

    List<object[]> toret = new List<object[]>();

    for (long propID = 0; propID < propList.Count(); ++propID)
    {
        var proptype = propList[propID].PropertyType;
        if (proptype.IsPrimitive || proptype == typeof(Decimal) || proptype == typeof(String))
        {
            toret.Add(new object[numElts + 1]);
            toret[toret.Count - 1][0] = propList[propID].Name;
            int row = 1;
            foreach (object item in data)
            {
                toret[toret.Count - 1][row] = propList[propID].GetValue(item, null);
                row++;
            }
        }
        else
        {
            var lst = (IList)Activator.CreateInstance((typeof(List<>).MakeGenericType(proptype)));
            foreach (object item in data)
            {
                lst.Add(propList[propID].GetValue(item, null));
            }
            List<object[]> serialisedProp = Serialise2D_Rec(lst);

        }
    }

    return toret;
}

答案 4 :(得分:0)

是的,因为lst的类型为object

您需要动态调用Serialise2D_Rec<T>()

的正确泛型类型