【问题标题】:Programmatic Manual JSON Deserialization into C# Object以编程方式手动将 JSON 反序列化为 C# 对象
【发布时间】:2018-06-06 23:37:55
【问题描述】:

我们有一个非常大的平面 C# 对象(20000 个属性),我们正在使用 Newtonsoft JSON Deserializer 将 JSON 对象反序列化到其中。

由于反射,目前需要 3 分钟以上。

我们正在寻求实现一个程序化的手动反序列化过程,以减少这个时间。

我们已经阅读了很多关于这方面的资源,这些资源给出了关于如何进行手动反序列化的一般概念,但没有解释如何以编程方式处理它。

例如

http://www.tomdupont.net/2016/01/how-to-optimize-jsonnet-serialization.html

How to improve JSON deserialization speed in .Net? (JSON.net or other?)

例如,我们有一个具有 20000 个属性且没有子类/对象属性的大型购买对象,实际上是 20000 多个字符串。它们当前从 JSON 映射的方式是我们在属性本身上有一个 JSON 属性,它对应于 JSON 本身的属性。

使用当前的方法反射非常慢,我们正在寻找正确的方向,以编程方式执行此操作。

【问题讨论】:

  • 您链接到的问题建议使用JsonReader/JsonWriter;你试过了吗?
  • 是的,我们已经尝试过了,它产生的结果非常微不足道,只节省了大约 5 秒。问题更多在于反射而不是大型对象堆。
  • 链接的答案中没有任何反映。
  • 如果它只是一个具有一堆字符串属性的对象,将其反序列化为Dictionary<string, string>会更快吗?

标签: c# json reflection json.net deserialization


【解决方案1】:

我不确定您要的是什么。听起来您想使用 JsonReader/JsonWriter 方法,但您不想手动编写 20,000 个 JSON 到属性的分配(例如 if (token.Value == "prop1") result.prop1 = token.Value)。如果是这种情况,那么您可以生成执行所需操作的源代码,并将结果包含在您的项目中。有很多方法可以做到这一点。这是一种方法:

using System;
using System.IO;
using System.Linq;
using System.Text;

namespace GetCustomAttribute
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            var sb = new StringBuilder();

            sb.AppendLine(@"
namespace GetCustomAttribute
{
    public static class PurchaseaOrderParser
    {
        public static void Parse(string jsonString, PurchaseOrder purchaseOrder)
        {

            var reader = new JsonTextReader(new StringReader(jsonString));

            var currentProperty = string.Empty;

            while (reader.Read())
            {
                if (reader.Value != null)
                {
                    if (reader.TokenType == JsonToken.PropertyName)
                        currentProperty = reader.Value.ToString();");

            var props = typeof(PurchaseOrder).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(IdAttribute)));
            foreach (var prop in typeof(PurchaseOrder).GetProperties())
            {
                var attribute = prop.GetCustomAttributes(typeof(IdAttribute), false).SingleOrDefault() as IdAttribute;
                if (attribute != null)
                {
                    var s = $"if (reader.TokenType == JsonToken.String && currentProperty == \"{attribute.Id}\") purchaseOrder.{prop.Name} = reader.Value.ToString();";
                    sb.AppendLine(s);
                }
            }

            sb.Append("}}}}}}");

            File.WriteAllText("PurchaseOrderParser.cs", sb.ToString());
        }
    }

    class PurchaseOrder
    {
        [Id("id")]
        public string Id { get; set; }

        [Id("name")]
        public string Name { get; set; }
    }

    class IdAttribute : Attribute
    {
        public string Id { get; set; }

        public IdAttribute(string id) => Id = id;
    }
}

产生:

namespace GetCustomAttribute
{
    public static class PurchaseaOrderParser
    {
        public static void Parse(string jsonString, PurchaseOrder purchaseOrder)
        {

            var reader = new JsonTextReader(new StringReader(jsonString));

            var currentProperty = string.Empty;

            while (reader.Read())
            {
                if (reader.Value != null)
                {
                    if (reader.TokenType == JsonToken.PropertyName)
                        currentProperty = reader.Value.ToString();
if (reader.TokenType == JsonToken.String && currentProperty == "id") purchaseOrder.Id = reader.Value.ToString();
if (reader.TokenType == JsonToken.String && currentProperty == "name") purchaseOrder.Name = reader.Value.ToString();
}}}}}}

.NET 还包括运行时代码生成功能。我对它们不熟悉,但您也许可以在运行时执行上述操作,这将确保解析器不会与 PurchaseOrder 类不同步。

【讨论】:

    猜你喜欢
    • 2011-03-09
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    相关资源
    最近更新 更多