В комментариях похоже, что вы решили прибегнуть к использованию Regex, чтобы избавиться от пустых объектов. Одна из проблем с этой идеей заключается в том, что она, вероятно, не будет обрабатывать ситуацию, когда у вас есть то, что я назову «рекурсивные пустые объекты». Другими словами, что-то вроде этого:
{
"foo":
{
"bar": {},
"baz": {}
}
}
Если вам удастся удалить самые глубокие уровни пустых объектов bar
и baz
с помощью Regex (при этом также понимая, что вам нужно удалить запятую между ними, чтобы сохраните 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())
{
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() == false) ||
(token.Type == JTokenType.Integer && token.Value() == 0) ||
(token.Type == JTokenType.Float && token.Value() == 0.0) ||
(token.Type == JTokenType.Null);
}
}
Затем вы можете сериализовать свой объект (ы) следующим образом:
var json = JsonHelper.SerializeToMinimalJson(obj);
Fiddle: https: // dotnetfiddle.net/awRPMR
EDIT
Если вы хотите почитать атрибут [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);
}
Fiddle: https://dotnetfiddle.net/0yVRI5