更新反序列化JSON对象的属性(没有定义的沙漠类型)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了更新反序列化JSON对象的属性(没有定义的沙漠类型)相关的知识,希望对你有一定的参考价值。

我将一些JSON作为字符串并将其存储为:

private static List<object> history = new List<object>();

var data = JsonConvert.DeserializeObject(parsedData);
history.Add(data);

JSON数据看起来像这样:

{ id: 12, data: 'my data' }

我想添加另一个迭代history列表的方法,通过其ID找到一个项目并更新它。

访问像这样的对象的属性的最佳方法是什么?

答案

如果传入的JSON字符串始终具有相同的字段,则可以将其序列化为已定义的类/类型。

public class JsonHistory
{
  public int id { get; set; }
  public string data { get; set; }
}

List<JsonHistory> history = new List<JsonHistory>();

var histData= JsonConvert.DeserializeObject<JsonHistory>(parsedData);
history.Add(histData);

然后,您还可以使用linq查找您要查找的任何匹配项:

var matches = history.Where(x => x.id == 10).Select(x => x.data);
另一答案

您可以使用dynamic而不是object,因为它更容易使用属性而不是object

List<dynamic> history = new List<dynamic>();
string parsedData = "{ id: 12, data: 'my data' }";
var data = JsonConvert.DeserializeObject<dynamic>(parsedData);
history.Add(data);
history.Add(data);
foreach (var o in history)
{
    o.id = 13;
}

另外,我强烈建议您创建一个类并将其用作已知类型。这将给你智能感知,你肯定会需要更进一步。

另一答案

JSON.NET documentation有以下方法,我也建议使用:

首先 - 反序列化为合理类型(匿名很好)

var json = "{id: 12, data: 'my data'}";
var definition = new { Id = 0, Data = "" }
var deserialised = JsonConvert.DeserializeAnonymousType(json, definition);

第二 - 你有第一个项目,所以你可以“欺骗”编译器让你在列表中使用匿名类型:

var history = (new[] { deserialised }).ToList();

然后,您可以将任何其他反序列化的实例推送到该列表中。

现在你可以进行过滤了:

var itemImLookingFor = history.SingleOrDefault(x => x.Id == 10);

一旦你得到了这个项目,你就可以更新它:

itemImLookingFor.Data = itemImLookingFor.Data.ToUpperCase()

我建议阅读this,因为它解释了使用dynamic关键字时固有的一些缺点;这不是一件坏事,它只是有它的位置。

对于这种情况,JSON.NET为您提供了所需的所有工具,可以反序列化为您自己定义的类型(例如,编写一个镜像JSON的类,或者像我在这里完成的匿名类型)。

另一答案

通常的方法是反序列化为自定义类或反序列化为JObject,这将允许您迭代其属性,如使用反射。两者都需要大量打字。

但是你可以使用一个聪明的小技巧,并获得强大类型的所有好处,而无需编写类。

使用匿名鸭子类型

将此方法添加到您的库中:

static public T JsonDeserialize<T>(string input, T template)
{
    return JsonConvert.DeserializeObject<T>(input);
}

一旦你有了这个,你可以通过提供一个示例实例来使用它来点击JSON(即让编译器推断出一个匿名类型)。这允许您使用匿名类型而不是键入自定义类。

例如,要获取ID为12的行,您可以执行以下操作:

using System;
using System.Linq;
using Newtonsoft.Json;


public class Program
{
    static public T JsonDeserialize<T>(string input, T example)
    {
        return JsonConvert.DeserializeObject<T>(input);
    }

    public static void Main()
    {
        //Sample data with two records
        const string input = @"[ { 'id' : 12, 'data' : 'MyData' }, { 'id' : 13, 'data' : 'Another record' } ]";

        //Create an example instance so the compiler can use its anonymous type
        var example = new []
                {
                    new { id = default(int), data = default(string) }
                };


        //Pass the example as argument 2 so that the compiler can infer T. The argument itself isn't used for anything.
        var list = JsonDeserialize(input, example);

        //Now we have a strongly-typed list, without having to write a class

        //We can use LINQ or anything else that needs a strong type
        foreach ( var o in list.Where( a => a.id == 12) )
        {
            Console.WriteLine(o.id);
            Console.WriteLine(o.data);  //Intellisense works here
        }


    }
}

输出:

12
MyData

Working example on DotNetFiddle

以上是关于更新反序列化JSON对象的属性(没有定义的沙漠类型)的主要内容,如果未能解决你的问题,请参考以下文章

如何根据json中的属性编写jackson反序列化器

c# 通过json.net中的JsonConverter进行自定义序列化与反序列化

讲解JAVA中JSON的反序列化

JSON 多态反序列化属性/类型丢失问题

json之jackson序列化反序列化探究(二)

json.net中属性的自定义反序列化[重复]