【问题标题】:How can I serialize and deserialize a type with a string member that contains "raw" JSON, without escaping the JSON in the process如何使用包含“原始”JSON 的字符串成员序列化和反序列化类型,而不在过程中转义 JSON
【发布时间】:2016-11-10 13:43:34
【问题描述】:

我想将 JSON 反序列化为对象,但我不想反序列化嵌套的 JSON,嵌套的 JSON 应转换为 JSON 列表(请检查“我的预期输出”以获得清晰的想法)。 ..

// 假设我有下面的 JSON 数据,这里我为“地址”实体嵌套了 JSON

String jsonEmployees =
"{"Employees":
[{"EmpId":1, "EmpName":"ABC", "Address":[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]},
{"EmpId":2, "EmpName":"XYZ", "Address":[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]}]
}"

public class Employee
{
    public int EmpId { get; set; }
    public string EmpName { get; set; }
    // **Note** : I'm not using List<Address> data type for Address, instead of I want list of address in JSON string
    public string Address { get; set; }
}

public class RootObject
{
    public List<Employee> Employees { get; set; }
}

var Employees = JsonConvert.DeserializeObject<RootObject>(jsonEmployees);

//我的预期输出

Employees[0].EmpId = 1;
Employees[0].EmpName = "ABC";
Employees[0].Address = "[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]";

Employees[1].EmpId = 2;
Employees[1].EmpName = "XYZ";
Employees[1].Address = "[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]";

请建议我解决此问题的最佳方法...

【问题讨论】:

    标签: c# json serialization deserialization


    【解决方案1】:

    您的问题是,如何序列化和反序列化具有包含“原始”JSON 的 string 成员的类型,而不在过程中转义 JSON?

    这可以通过使用JsonWriter.WriteRawValue()JRaw.Create() 读写原始JSON 的custom JsonConverter 来完成:

    public class RawConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            throw new NotImplementedException();
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var raw = JRaw.Create(reader);
            return raw.ToString();
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var s = (string)value;
            writer.WriteRawValue(s);
        }
    }
    

    然后将其应用于您的类型,如下所示:

    public class Employee
    {
        public int EmpId { get; set; }
        public string EmpName { get; set; }
        // **Note** : I'm not using List<Address> data type for Address, instead of I want list of address in JSON string
        [JsonConverter(typeof(RawConverter))]
        public string Address { get; set; }
    }
    
    public class RootObject
    {
        public List<Employee> Employees { get; set; }
    }
    

    示例fiddle

    请注意,原始 JSON 字符串必须表示有效的 JSON。如果没有,那么创建的 JSON 将不可读。如果要保证 JSON 字面量有效,可以在内部保持 JSON 处于解析状态:

    public class Employee
    {
        public int EmpId { get; set; }
        public string EmpName { get; set; }
    
        [JsonProperty("Address")]
        JToken AddressToken { get; set; }
    
        [JsonIgnore]
        public string Address
        {
            get
            {
                if (AddressToken == null)
                    return null;
                return AddressToken.ToString(Formatting.Indented); // Or Formatting.None if you prefer
            }
            set
            {
                if (value == null)
                    AddressToken = null;
                else
                    // Throw an exception if value is not valid JSON.
                    AddressToken = JToken.Parse(value);
            }
        }
    }
    

    此实现不需要转换器。

    【讨论】:

    • 谢谢@dbc ...它解决了我的问题两种解决方案都运行良好...再次感谢您提供宝贵的解决方案...跨度>
    【解决方案2】:

    我认为你将不得不重建你的员工名单:

            RootObject Employees = JsonConvert.DeserializeObject<RootObject>(jsonEmployees);
    
            List<Employee> EmployeesNew = new List<Employee>();
    
            foreach (var item in Employees.Employees)
            {
                string StringAddress = JsonConvert.SerializeObject(item.Address, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
                EmployeesNew.Add(new Employee { EmpId = item.EmpId, EmpName = item.EmpName, AddressString = StringAddress });
    
            }
    

    你的班级:

        public class Employee
        {
            public int EmpId { get; set; }
            public string EmpName { get; set; }
            // **Note** : I'm not using List<Address> data type for Address, instead of I want list of address in JSON string
            public List<AddressItems> Address { get; set; }
            public string AddressString { get; set; }
        }
    
        public class RootObject
        {
            public List<Employee> Employees { get; set; }
        }
    
        public class AddressItems
        {
            public int AddressId { get; set; }
            public string Address { get; set; }
        }
    

    【讨论】:

    • Yanga - 我认为这对我有用,但过程有点冗长......我的问题已由 dbc 解决......感谢您宝贵的时间......
    【解决方案3】:

    在 JSON 中,大括号 {} 是对象的符号,方括号 [] 是数组。

    只要您的数组像这样封装在大括号中,您就必须使用另一个包含对象。如果你可以去掉{"Employees":前缀和}后缀,你应该可以直接将JSON转换为员工列表。

    编辑:对不起,我不明白这个问题。

    做你想做的事情要么真的很简单,要么真的很困难,这取决于你是否可以控制 JSON。

    如果您可以控制 JSON,您需要做的就是在地址值周围添加单引号,使其看起来像这样:

    [{"EmpId":1, "EmpName":"ABC", "Address":'[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]'},
    

    就是这样!现在序列化器会将其转换为字符串。

    如果不能,则必须自己反序列化 JSON,逐个令牌。或者你可以做一个变通方法,创建一个对应的地址类,让序列化器转换成它。然后添加计算属性并使用序列化程序将地址反序列化回 JSON。
    (丑陋,我知道,但实施起来会快得多)。

    【讨论】:

    • 我能够将上面的 JSON 转换为员工列表。但我的问题是如何将 JSON 上的反序列化(转换)为 Employee 对象,以便我的地址实体数据将采用 JSON 格式列表。请检查我的预期输出......如果我期待一些不可能的事情,请纠正我,或者告诉我你的解决方案是否适用......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多