【问题标题】:How to Serialize and Deserialize ArrayList of Arrays by using Json.NET如何使用 Json.NET 对数组的 ArrayList 进行序列化和反序列化
【发布时间】:2017-01-10 08:57:56
【问题描述】:

我需要在我的应用程序中使用 JSON.NET 将对象序列化/反序列化为 json。 Object 的属性类型为 ArrayList,其中包含字符串数组。为了模拟它,我编写了以下单元测试;

public class JsonTests
{
    public class MyTestClass
    {
        public ArrayList Items { get; private set; }

        public MyTestClass()
        {
            this.Items = new ArrayList();
        }
    }
    [Fact]
    public void JsonConvert_Should_Serialize_ArrayList_And_Deserialize_Successfully()
    {
        MyTestClass myObject = new MyTestClass();
        myObject.Items.Add(new string[] { "Test1", "Test2" });
        string jsonResult = JsonConvert.SerializeObject(myObject);            
        MyTestClass tempMyObject = JsonConvert.DeserializeObject<MyTestClass>(jsonResult);
         //(tempMyObject.Items[0] as string[]) casts to null therefore it throws exception
        Assert.Equal((myObject.Items[0] as string[])[0], (tempMyObject.Items[0] as string[])[0]);
    } 
}

在序列化期间它不会抛出任何异常。但是,它不能正确反序列化 ArrayList。

我的问题是,如何将它反序列化回字符串数组的 ArrayList?

更新:此外,我无法更改类定义。该类是在我无法编辑该类的程序集中实现的。

【问题讨论】:

  • 您是否提前知道 JSON 将包含一个锯齿状的二维字符串数组,还是需要从 JSON 中推断出ArrayList 项类型?

标签: c# json serialization json.net


【解决方案1】:

ArrayList 是一个非泛型、无类型的集合,因此您需要告知 Json.NET 项目的预期类型。一种方法是为ArrayList 使用custom JsonConverter

public class ArrayListConverter<TItem> : JsonConverter
{
    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var list = serializer.Deserialize<List<TItem>>(reader);
        var arrayList = existingValue as ArrayList ?? new ArrayList(list.Count);
        arrayList.AddRange(list);
        return arrayList;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ArrayList);
    }
}

然后将转换器应用到类中,如下所示:

public class MyTestClass
{
    [JsonConverter(typeof(ArrayListConverter<string []>))]
    public ArrayList Items { get; private set; }

    public MyTestClass()
    {
        this.Items = new ArrayList();
    }
}

示例fiddle

如果无法修改类,并且您希望对象图中ArrayList所有实例 将其项目反序列化为string [],则可以将转换器添加到JsonSerializerSettings.Converters 而不是将其添加到类型中:

var tempMyObject = JsonConvert.DeserializeObject<MyTestClass>(jsonResult,
                                                              new JsonSerializerSettings { Converters = { new ArrayListConverter<string []>() } });

示例fiddle #2

最后,如果无法修改类,并且您只希望MyTestClass 中的特定ArrayList Items 属性将其项目反序列化为string [],则需要为MyTestClass 创建一个自定义转换器。您可以使用 Custom deserializer only for some fields with json.NET 中的模式自定义反序列化 ArrayList 属性,同时使用默认反序列化填充其余部分:

public class MyTestClassConverter : JsonConverter
{
    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var root = existingValue as MyTestClass ?? (MyTestClass)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
        var jsonObject = JObject.Load(reader);

        var jsonItems = jsonObject["Items"].RemoveFromLowestPossibleParent();
        if (jsonItems != null && jsonItems.Type != JTokenType.Null)
        {
            root.Items.AddRange(jsonItems.ToObject<List<string []>>());
        }
        // Populate the remaining standard properties
        using (var subReader = jsonObject.CreateReader())
        {
            serializer.Populate(subReader, root);
        }
        return root;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(MyTestClass).IsAssignableFrom(objectType);
    }
}

public static class JsonExtensions
{
    public static JToken RemoveFromLowestPossibleParent(this JToken node)
    {
        if (node == null)
            return null;
        var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
        if (contained != null)
            contained.Remove();
        // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
        if (node.Parent is JProperty)
            ((JProperty)node.Parent).Value = null;
        return node;
    }
}

然后按如下方式使用:

var tempMyObject = JsonConvert.DeserializeObject<MyTestClass>(jsonResult,
                                                              new JsonSerializerSettings { Converters = { new MyTestClassConverter() } });

示例fiddle #3

【讨论】:

  • 感谢您的回复。这回答了我的问题。但是,我忘了在我的问题中提到一些东西。我无法更改类定义,该类是在我无法编辑类实现的程序集中实现的,因此我无法在属性上添加任何属性。在这种情况下,我如何将您的解决方案应用于我的问题?
  • @BorisZolotov - 这是唯一要反序列化的ArrayList,还是对象图中还有其他@BorisZolotov?
  • 是的,对象中还有其他属性。我需要序列化/反序列化整个对象。对象的属性之一是 ArrayList 类型,我只对 ArrayList 有问题。
  • @BorisZolotov - 不,我的意思是这是您的对象图中ArrayList 的唯一实例?或者其他地方可能有一个ArrayList,比如整数?
  • ArrayList 只包含对象类型的字符串数组。
【解决方案2】:

试试这个,希望这段代码对你有帮助

使用 ListJSON.NET

List<string[]> list = new List<string[]>();

list.Add(new string[] { "Value","value" });
list.Add(new string[] { "b2", "b22" });

var ee = JsonConvert.SerializeObject(list);

Console.WriteLine(ee);

List<string[]> ll = JsonConvert.DeserializeObject<List<string[]>>(ee);


foreach (var Valus in ll)
{
    foreach (var val in Valus)
    {
         Console.WriteLine(val);
    }
}

使用数组列表

string[][] strarry = { new string[] { "f1", "f2", "f3" }, new string[] { "s1", "s2", "s3" }, new string[] { "t1", "t2", "t3" } };

string SerializeArray = json.Serialize(strarry);

string[][] DeSerializeArrayList = json.Deserialize<string[][]>(SerializeArray);

foreach (var item in DeSerializeArrayList)
{
      foreach (var Subitem in item)
      {
              Response.Write(Subitem + "<br/>");
      } 
}

使用列表

List<Data> list = new List<Data>();

list.Add(new Data() { ID = 1, Name = "val1" });
list.Add(new Data() { ID = 2, Name = "val2" });
JavaScriptSerializer json = new JavaScriptSerializer();

string Serialize = json.Serialize(list);
Response.Write(Serialize);

List<Data> DeSerialize = json.Deserialize<List<Data>>(Serialize);

foreach (var Data in DeSerialize)
{
    Response.Write(Data.Name);
}

数据类

public class Data
{
    public int ID { get; set; }
    public string Name { get; set; }
}

【讨论】:

  • 我正在寻找一个解决方案,将 NewtonSoft 的 JSON.NET API 与 System.Collections.ArrayList 结合使用。
  • ArrayList 没有泛型类型,但 list 是泛型类型,如果您想使用字符串数组的 ArrayList 反序列化 json,则会出错,但您使用字符串数组的列表成功运行而不会出错。所以如果你想要这个使用 List 和 NewtonSoft 的 JSON.NET API 告诉我我有代码。
猜你喜欢
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 2015-06-28
相关资源
最近更新 更多