如何将JSON字典序列化/反序列化为数组

Arjay H.

需要将C#字典序列化和反序列化为JSON数组。我也想使用数组索引符号从powershell中读取JSON。

默认情况下,JSON格式为:

{
 "defaultSettings": {
  "applications": {
   "Apollo": {
    "environments": {
      "DEV": {
        "dbKeyTypes": {
          "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06",
          "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
        }
      },
      "TST": {
        "dbKeyTypes": {
          "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06",
          "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
        }
      }
    }
  },
  "Gemini": {
    "environments": {
      "DEV": {
        "dbKeyTypes": {
          "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06",
          "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
        }
      },
      "TST": {
        "dbKeyTypes": {
          "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06",
          "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
        }
      }
    }
   }
  }
 }
}

使用.Net Core中的默认json阅读器,此方法效果很好,但不允许我在PowerShell中使用数组索引符号。

相反,我正在寻找的是这样的:

{
 "defaultSettings": {
  "applications": [
   {
     "Apollo": {
      "environments": [
        {
          "DEV": {
            "dbKeyTypes": [
              {
                "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06"
              },
              {
                "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
              }
            ]
          }
        },
        {
          "TST": {
            "dbKeyTypes": [
              {
                "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06"
              },
              {
                "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
              }
            ]
          }
        }
      ]
    }
  },
  {
    "Gemini": {
      "environments": [
        {
          "DEV": {
            "dbKeyTypes": [
              {
                "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06"
              },
              {
                "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
              }
            ]
          }
        },
        {
          "TST": {
            "dbKeyTypes": [
              {
                "DmkPassword": "AEikOooIuGxXC9UBJQ3ckDj7Q126tB06"
              },
              {
                "SymmetricKeySource": "bTU7XOAYA2FFifmiBUggu99yHxX3Ftds"
              }
            ]
          }
        }
      ]
    }
   }
  ]
 }
}

我正在使用从序列化Dictionary <string,string>的WriteJson部分到“名称”:“值”数组

这很好用;但是,当然,由于ReadJson()未实现方法,因此无法读取。顺便说一句,为了获得上述所需的json格式,我将链接中的CustomDictionaryConverter修改为:

writer.WritePropertyName(key.ToString());
//writer.WriteValue(key);
//writer.WritePropertyName("value");
serializer.Serialize(writer, valueEnumerator.Current);

实现背后的类是:

public enum DeploymentEnvironment { DEV = 1, TST = 2 }
public enum TargetApplication { Apollo = 1, Gemini = 2 }
public enum DbKeyType { DmkPassword = 1, SymmetricKeySource = 2 }

public class DeploymentSettings
{
    [JsonProperty("defaultSettings")]
    public DefaultSettings DefaultSettings { get; set; }
    public DeploymentSettings()
    {
        DefaultSettings = new DefaultSettings();
    }
}

public partial class DefaultSettings
{
    [JsonProperty("applications")]
    public Dictionary<TargetApplication, ApplicationContainer> Applications { get; set; }

    public DefaultSettings()
    {
        Applications = new Dictionary<TargetApplication, ApplicationContainer>();
    }
}

public partial class ApplicationContainer
{
    [JsonProperty("environments")]
    public Dictionary<DeploymentEnvironment, EnvironmentContainer> Environments { get; set; }
    public ApplicationContainer()
    {
        Environments = new Dictionary<DeploymentEnvironment, EnvironmentContainer>();
    }
}

public partial class EnvironmentContainer
{
    [JsonProperty("dbKeyTypes")]
    public Dictionary<DbKeyType, string> DbKeyTypes { get; set; }

    public EnvironmentContainer()
    {
        DbKeyTypes = new Dictionary<DbKeyType, string>();
    }
}

我将对象序列化如下: var json = JsonConvert.SerializeObject(ds, Formatting.Indented, new CustomDictionaryConverter());

如前所述,序列化ReadJson()是可行的,但是我需要帮助编写方法才能进行反序列化。

数据库

您可以扩展CustomDictionaryConverter阅读和写作,如下所示:

public class CustomDictionaryConverter : JsonConverter
{
    // Adapted from CustomDictionaryConverter from this answer https://stackoverflow.com/a/40265708
    // To https://stackoverflow.com/questions/40257262/serializing-dictionarystring-string-to-array-of-name-value
    // By Brian Rogers https://stackoverflow.com/users/10263/brian-rogers

    sealed class InconvertibleDictionary : Dictionary<object, object>
    {
        public InconvertibleDictionary(DictionaryEntry entry)
            : base(1)
        {
            this[entry.Key] = entry.Value;
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(IDictionary).IsAssignableFrom(objectType) && objectType != typeof(InconvertibleDictionary);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Lazy evaluation of the enumerable prevents materialization of the entire collection of dictionaries at once.
        serializer.Serialize(writer,  Entries(((IDictionary)value)).Select(p => new InconvertibleDictionary(p)));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
            return null;
        var dictionary = existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
        switch (reader.TokenType)
        {
            case JsonToken.StartObject:
                serializer.Populate(reader, dictionary);
                return dictionary;

            case JsonToken.StartArray:
                {
                    while (true)
                    {
                        switch (reader.ReadToContentAndAssert().TokenType)
                        {
                            case JsonToken.EndArray:
                                return dictionary;

                            case JsonToken.StartObject:
                                serializer.Populate(reader, dictionary);
                                break;

                            default:
                                throw new JsonSerializationException(string.Format("Unexpected token {0}", reader.TokenType));
                        }
                    }
                }

            default:
                throw new JsonSerializationException(string.Format("Unexpected token {0}", reader.TokenType));
        }
    }

    static IEnumerable<DictionaryEntry> Entries(IDictionary dict)
    {
        foreach (DictionaryEntry entry in dict)
            yield return entry;
    }
}

public static partial class JsonExtensions
{
    public static JsonReader ReadToContentAndAssert(this JsonReader reader)
    {
        return reader.ReadAndAssert().MoveToContentAndAssert();
    }

    public static JsonReader MoveToContentAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (reader.TokenType == JsonToken.None)       // Skip past beginning of stream.
            reader.ReadAndAssert();
        while (reader.TokenType == JsonToken.Comment) // Skip past comments.
            reader.ReadAndAssert();
        return reader;
    }

    public static JsonReader ReadAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (!reader.Read())
            throw new JsonReaderException("Unexpected end of JSON stream.");
        return reader;
    }
}

然后,您可以DeploymentSettings使用以下设置序列化和反序列化

var settings = new JsonSerializerSettings
{
    Converters = { new CustomDictionaryConverter(), new StringEnumConverter() }
};

var ds = JsonConvert.DeserializeObject<DeploymentSettings>(json, settings);

var json2 = JsonConvert.SerializeObject(ds, Formatting.Indented, settings);

笔记:

  • 此版本转换器避免加载整个字典到一个临时JArray层次结构,无论是ReadJson()WriteJson(),而是直接从和到JSON流流。

  • 因为现在使用序列化程序直接序列化各个词典条目,StringEnumConverter所以正确命名键是必需的。(如果DateTime您在任何地方都使用这样的字典,则使用序列化程序还可以确保数字或键正确地国际化。)

  • 由于Json.NET支持注释,因此转换器会检查并跳过注释,这增加了一点复杂性。(我希望有一种方法可以JsonReader默默地跳过评论。)

演示在这里摆弄

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何将嵌套的Json数组反序列化为字典?

如何将结构反序列化/序列化为没有键的数组

如何将 JSON 文件序列化和反序列化为 DataTable 以填充 DataGridView?

如何将嵌套的哈希表序列化/反序列化为JSON?

如何将数组反序列化为包装对象?

使用Jackson将反序列化JSON数组反序列化为Map

使用Jackson将反序列化JSON数组反序列化为单个Java对象

如何将未类型化值的多态字典的值反序列化为常规.Net数组?

如何将JSON反序列化为.net对象

如何将 JSON 对象反序列化为 DataTable

如何将Json反序列化为对象?

如何将Riak备份反序列化为JSON?

如何将 JSON 流反序列化为 JToken?

如何使用Jackson将反序列化的JSON反序列化为忽略键的对象?

反序列化Json数组字典对

您如何将JSON反序列化为F#中的记录的地图/字典?

如何将 xml 序列化/反序列化为 C# 对象?

如何将JVM对象序列化和反序列化为String?

如何将多个对象序列化/反序列化为单个XML文件?

如何使用Jackson将Java Enums序列化和反序列化为JSON对象

如何将伪JSON数组反序列化为C#

如何将JSON对象数组反序列化为C#匿名类型?

如何将JSON数组反序列化为本地.net数据结构?

如何将包含不同数据类型的JSON数组反序列化为单个对象

如何将 JSON 嵌套对象数组反序列化为 C# 对象

如何将数组序列化为json对象?

使用动态键将JSON反序列化为字典

将 json 反序列化为对象和字典

将JSON反序列化为字典无法正常工作