我可以在运行时调用泛型方法时指定 'T' (可能使用反射)吗?

Can I specify 'T' when invoking at generic method at runtime (probably using reflection)?

我有许多 JSON 个文件,每个文件都包含一个不同 class 对象的列表。

我可以从文件名中计算出我期望的数据,并且有一个通用的 JSON 文件 reader,其中 returns 是正确的数据,但我无法弄清楚如何将其分配给调用方法中允许我以实际类型访问结果的任何内容。

我目前正在使用这条线路:

var k = ReadJson<dynamic>(filePath, typeof(List<>).MakeGenericType(new[] { type }));

var k = ReadJson<Object>(filePath, typeof(List<>).MakeGenericType(new[] { type }));

但他们都给了我

Unable to cast object of type 'System.Collections.Generic.List`1[Abc.Shared.Models.Location]' to type 'System.Collections.Generic.List`1[System.Object]'.

猜想:既然不能直接调用ReadJson,能不能通过指定泛型类型的反射来调用ReadJson'T'?如果可能的话,我一直无法锻炼。

(为了完整起见,这里是通用方法 - 我不认为问题出在这里)

    public static List<T> ReadJson<T>(string filePath, Type t) where T : class, new()
    {
        List<T> regions = new List<T>();

        using (StreamReader file = System.IO.File.OpenText(filePath))
        {
            JsonSerializer serializer = new JsonSerializer();
            regions = (List<T>)serializer.Deserialize(file, t);
        }

        return regions;
    }

尝试以下操作:

public static List<T> ReadJson<T>(string filePath)
{
    using (var reader = File.OpenText(filePath))
    {
        var serializer = new JsonSerializer();
        return (List<T>) serializer.Deserialize(reader, typeof(List<T>));
    }
}

public static IList ReadJson(string filePath, Type itemType)
{
    using (var reader = File.OpenText(filePath))
    {
        var serializer = new JsonSerializer();
        var type = typeof(List<>).MakeGenericType(itemType);
        return (IList)serializer.Deserialize(reader, type);
    }
}

如果您在设计时知道项目类型,则可以使用第一个版本。如果您在设计时不知道项类型,但在运行时知道,则可以使用第二个版本。在任何情况下,这两种方法 return 都是 itemType/T 项的列表。

第二个版本声明为returnIList。这是我们所能做的,因为我们在设计时不知道项目类型。然而,它 return 是真实的 List<T>

你的ReadJson方法是多余的,如果你知道T那么你就知道t,因为t = typeof(T)。或者你的意思是 t = typeof(List<T>)

您不能将 List<T> 转换为 List<TBase>(并且 object 是所有引用类型的基础),因为 List<T> 不是协变的。您可以将 IEnumerable<T> 转换为 IEnumerable<TBase>,因为 IEnumerable<T>covariant. For historical reasons even arrays are covariant,因此您可以将 T[] 转换为 TBase[]。我会给你两个样本:

public static IEnumerable<T> ReadJson1<T>(string filePath, Type t) where T : class, new()
{
    IEnumerable<T> regions = new List<T>();

    using (StreamReader file = System.IO.File.OpenText(filePath))
    {
        JsonSerializer serializer = new JsonSerializer();
        regions = (IEnumerable<T>)serializer.Deserialize(file, t);
    }

    return regions;
}

public static T[] ReadJson2<T>(string filePath, Type t) where T : class, new()
{
    using (StreamReader file = System.IO.File.OpenText(filePath))
    {
        JsonSerializer serializer = new JsonSerializer();
        var regions = (T[])serializer.Deserialize(file, t);
        return regions;
    }
}

Type type = typeof(MyObject);
IEnumerable<object> k1 = ReadJson1<object>("test.json", typeof(List<>).MakeGenericType(new[] { type }));
object[] k2 = ReadJson2<object>("test.json", type.MakeArrayType());