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

问题描述 投票:0回答:2

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

我可以从文件名中计算出我期望的数据类,并且我有一个通用的 JSON 文件读取器,它可以返回正确的数据。但是,我不知道如何将其分配给调用方法中的任何内容,以允许我以实际类型访问结果。

我目前正在使用这条线:

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

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

但他们都给了我

无法转换类型的对象 'System.Collections.Generic.List`1[Abc.Shared.Models.Location]' 到 输入“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;
    }
c# generics reflection
2个回答
1
投票

您无法将

List<T>
转换为
List<TBase>
(并且
object
是所有引用类型的基础),因为
List<T>
不是协变的。您可以将
IEnumerable<T>
转换为
IEnumerable<TBase>
,因为
IEnumerable<T>
协变由于历史原因,即使数组也是协变的,因此您可以将
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());

0
投票

尝试以下操作:

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

如果您在设计时知道项目类型,则可以使用第一个版本。如果您在设计时不知道项目类型,但在运行时知道,则可以使用第二个版本。在任何情况下,这两种方法都会返回一个

itemType/T
项目列表。

第二个版本声明返回

IList
。这是我们所能做的,因为我们在设计时不知道项目类型。然而它返回一个真正的
List<T>

你的

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

© www.soinside.com 2019 - 2024. All rights reserved.