本文介绍了如何忽略生成的JSON中的空对象文字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我使用Json.NET
将复杂的C#
对象图转换为JSON。由于忽略对象中具有默认值的属性,我通常会在输出中得到空的对象文字,我希望将其省略。
例如:
public class Sample {
public int Value { get; set; }
public string Name { get; set; }
}
public class ParentSample {
// this property should never be null, hence the initializer
public Sample Sample { get; } = new Sample();
}
..
var obj = new ParentSample();
// settings for indentation and excluding default values omitted for clarity
var output = JsonConvert.SerializeObject(obj, ... );
// output will be
// {
// Sample: {}
// }
//
// I'd like it to be
// {}
我知道一些特定于类型的解决方案,比如向ParentSample
类型添加ShouldSerializeSample
布尔方法,并检查是否所有属性都是默认的。但是,我想要一个通用的解决方案,例如,自定义合同解析器。
推荐答案
在注释中,您似乎已经决定使用正则表达式来清除空对象。这个想法的一个问题是,它可能不能处理我称之为"递归空对象"的情况。换句话说,大概是这样的:
{
"foo":
{
"bar": {},
"baz": {}
}
}
如果您使用Regex成功删除了最深层的空对象bar
和baz
(同时还意识到需要删除它们之间的逗号以保持JSON有效),则仍将留下一个空对象:foo
。
{
"foo":
{
}
}
我认为更好的解决方案是将数据加载到JToken
层次结构中,然后在将其写出到JSON之前使用递归方法删除所有空子对象。这样的功能应该可以满足您的需求:
using System;
using Newtonsoft.Json.Linq;
public static class JsonHelper
{
public static string SerializeToMinimalJson(object obj)
{
return JToken.FromObject(obj).RemoveEmptyChildren().ToString();
}
public static JToken RemoveEmptyChildren(this JToken token)
{
if (token.Type == JTokenType.Object)
{
JObject copy = new JObject();
foreach (JProperty prop in token.Children<JProperty>())
{
JToken child = prop.Value;
if (child.HasValues)
{
child = child.RemoveEmptyChildren();
}
if (!child.IsEmptyOrDefault())
{
copy.Add(prop.Name, child);
}
}
return copy;
}
else if (token.Type == JTokenType.Array)
{
JArray copy = new JArray();
foreach (JToken item in token.Children())
{
JToken child = item;
if (child.HasValues)
{
child = child.RemoveEmptyChildren();
}
if (!child.IsEmptyOrDefault())
{
copy.Add(child);
}
}
return copy;
}
return token;
}
public static bool IsEmptyOrDefault(this JToken token)
{
return (token.Type == JTokenType.Array && !token.HasValues) ||
(token.Type == JTokenType.Object && !token.HasValues) ||
(token.Type == JTokenType.String && token.ToString() == String.Empty) ||
(token.Type == JTokenType.Boolean && token.Value<bool>() == false) ||
(token.Type == JTokenType.Integer && token.Value<int>() == 0) ||
(token.Type == JTokenType.Float && token.Value<double>() == 0.0) ||
(token.Type == JTokenType.Null);
}
}
然后可以按如下方式序列化对象:
var json = JsonHelper.SerializeToMinimalJson(obj);
小提琴:https://dotnetfiddle.net/awRPMR
编辑
如果您想使用此方法来支持[DefaultValue]
属性,您可以通过修改SerializeToMinimalJson()
方法来创建JsonSerializer
的实例,在其上设置DefaultValueHandling
属性,然后将其传递给JToken.FromObject()
,如下所示。(必须以这种方式完成,因为JTokens
没有对使用FromObject()
创建它们的原始对象的引用,因此无法在此之后获取[DefaultValue]
属性的值。)
public static string SerializeToMinimalJson(object obj)
{
var serializer = new JsonSerializer();
serializer.NullValueHandling = NullValueHandling.Ignore;
serializer.DefaultValueHandling = DefaultValueHandling.Ignore;
return JToken.FromObject(obj, serializer).RemoveEmptyChildren().ToString();
}
如果这样做,您可能还希望更改IsEmptyOrDefault()
方法,以便它不会删除"默认"的值。您可以将其简化为:
public static bool IsEmptyOrDefault(this JToken token)
{
return (token.Type == JTokenType.Array && !token.HasValues) ||
(token.Type == JTokenType.Object && !token.HasValues);
}
小提琴:https://dotnetfiddle.net/0yVRI5
这篇关于如何忽略生成的JSON中的空对象文字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!