通用类型JsonConvert.DeserializeObject<List<T>>(string)

10

我正在使用Newtonsoft.JSON。我不知道传递给该方法的对象的类型,或从该方法检索的对象的类型,因此我尝试在一个我不知道其类型的对象上使用DeserializeObject

这种做法可行吗?如果可以,如何实现?以下是我的代码。

public static List<T> GetObject<T>(string cacheKey, IEnumerable<T> obj)
{
    using (HttpClient client = new HttpClient())
    {
        var response = client.GetAsync("http://localhost:53805/api/NonPersisted/Get/" + cacheKey).Result;

        obj = JsonConvert.DeserializeObject<obj.GetType>(response.Content.ToString());
        return obj.ToList();
    }            
}

我首先尝试使用

obj = JsonConvert.DeserializeObject<List<T>>(response.Content.ToString());

显然,这不起作用,它无法解析。 获取对象类型并不能建立,它说obj是一个变量但被用作类型

编辑 似乎你可以使用一个泛型的List<T>而不知道类型,使用JsonConvert.DeserializeObject<>。真正的错误是 response.Content 只返回了类型。你需要有...

obj = JsonConvert.DeserializeObject<List<T>>(response.Content.ReadAsStringAsync().Result);

JsonConvert.DeserializeObject<List<T>> 没有起作用吗? - Chetan
使用动态 obj = JsonConvert.DeserializeObject<dynamic>(response.Content);,然后像 obj.MyCustomProperty 一样访问您的属性,怎么样? - DolceVita
@ChetanRanpariya 我知道它始终会是一个列表,但我不能将其强制转换为我不知道的类型。通常你会写 JsonConvert.DeserializeObject<SomeObject>,然后它就知道所有属性,所以它可以将其转换为类型 SomeObject。在我的情况下,我无法对 List<T> 进行强类型化。 - christopher clark
顺便问一下,你确定你的 API 总是返回对象列表而不是单个对象吗?我不明白为什么在你的情况下 DeserializeObject<List<T>> 不起作用。你的 JSON 结构可能有问题。 - DolceVita
@maccettura 我不能保证那些将使用dll中的“GetObject”方法的开发人员能够使用异步。我可以采用锁定方式,但那篇文章真是太好了,谁知道其中引起了多少问题。 - christopher clark
显示剩余8条评论
4个回答

8
您可以使GetObject方法成为泛型,而无需使用参数IEnumerable<T> obj
我建议采用以下解决方案,并假设您知道从URL返回的JSON值的格式。
例如,该URL返回包含项目数组的JSON,每个项目都有两个属性firstNamelastName
var response = "[{\"firstName\":\"Melanie\",\"lastName\":\"Acevedo\"},
    {\"firstName\":\"Rich\",\"lastName\":\"Garrett\"},
    {\"firstName\":\"Dominguez\",\"lastName\":\"Rose\"},
    {\"firstName\":\"Louisa\",\"lastName\":\"Howell\"},
    {\"firstName\":\"Stone\",\"lastName\":\"Bean\"},
    {\"firstName\":\"Karen\",\"lastName\":\"Buckley\"}]";

我可以按照以下方式编写GetObject方法。

public static List<T> GetObject<T>()
{
    var response = "
        [{\"firstName\":\"Melanie\",\"lastName\":\"Acevedo\"},
        {\"firstName\":\"Rich\",\"lastName\":\"Garrett\"},
        {\"firstName\":\"Dominguez\",\"lastName\":\"Rose\"},
        {\"firstName\":\"Louisa\",\"lastName\":\"Howell\"},
        {\"firstName\":\"Stone\",\"lastName\":\"Bean\"},
        {\"firstName\":\"Karen\",\"lastName\":\"Buckley\"}]";

    var obj = JsonConvert.DeserializeObject<List<T>>(response);
        return obj.ToList();
}

以上方法中的T可以是任何具有firstNamelastName属性的类型。例如:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
}

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public double Salary { get; set; }
}

我可以通过传递PersonEmployee来调用GetObject方法,并将JSON字符串反序列化为这些类的对象集合,如下所示。

var persons = GetObject<Person>();

foreach (var item in persons)
{
    Console.WriteLine($"{item.FirstName} {item.LastName}");
}

var employees = GetObject<Employee>();

foreach (var item in employees)
{
    Console.WriteLine($"{item.FirstName} {item.LastName}");
}

总的来说,我想要表达的意思是如果了解JSON的格式,将适当的类型传递给JsonConvert.Deserialize<T>应该不会有任何问题。
如果传入的JSON表示一个集合,并尝试将其反序列化为简单类,则会失败,反之亦然也不起作用。
因此,对于您的问题,如果您知道JSON将是一个集合,那么使用JsonConvert.Deserialize<List<T>>应该不会给您带来任何问题,只要T具有可以从JSON中设置值的属性。
我希望这能帮助您解决问题。

我将此标记为正确,因为似乎可以使用JsonConvert.Deserialize<List<T>>。实际上,我的回复内容中存在错误。我将编辑我的答案以包括这个问题。 - christopher clark

2
我认为如果您不知道类型T,就不能调用Deserialize<T>(..)。 我能想到的唯一办法是获取对象:
    public static Object GetObject(string cacheKey)
    {
        using (HttpClient client = new HttpClient())
        {
            var response = client.GetAsync("http://localhost:53805/api/NonPersisted/Get/" + cacheKey).Result;

            var obj = JsonConvert.DeserializeObject(response.Content.ToString());
            return obj;
        }

    }

我认为这将是最简单的解决方案。对于开发人员来说可能更容易,但一个转换不应该难倒他们! - christopher clark

1

我现在没有测试的条件,但我认为以下方法可能有效。我发现JSON.NET在反序列化时不喜欢List<T>,我通常通过使用数组来解决这个问题。

static HttpClient _httpClient = new HttpClient();
public static async Task<T[]> GetObject<T>(string cacheKey)
{
    HttpResponseMessage response = await _httpClient .GetAsync("http://localhost:53805/api/NonPersisted/Get/" + cacheKey);

    return JsonConvert.DeserializeObject<T[]>(response.Content.ToString());
}   

我擅自移除了 HttpClientusing 语句,并将其改为静态成员。我还将该方法改为运行 async,你可以轻松地将其改回来,但正如我在评论中提到的,你可能希望避免使用 HttpClient,而改用WebClient

response.Content.ToString() 一直是问题所在。正确的方式是 response.Content.ReadAsStringAsync().Result - christopher clark

0

您可以在不强制类型的情况下将类型传递到函数中来实现此操作。 例如:

Type type = obj.GetType();  
JsonConvert.DeserializeObject(json, type);   

这会返回一个对象,而不是问题所需的List<T>。 - Tom McDonough

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接