我想避免在序列化数据时重新发明轮子。我知道一些序列化彼此链接的对象的方法,但是范围从编写一些代码到编写大量用于序列化的代码,我希望避免这种情况。必须有一些通用的解决方案。
假设我有一个这样的结构:
Person
bro = new Person { name = "bro", pos = new Pos { x = 1, y = 5 } },
sis = new Person { name = "sis", pos = new Pos { x = 2, y = 6 } },
mom = new Person { name = "mom", pos = new Pos { x = 3, y = 7 },
children = new List<Person> { bro, sis }
},
dad = new Person { name = "dad", pos = new Pos { x = 4, y = 8 },
children = new List<Person> { bro, sis }, mate = mom
};
mom.mate = dad;
Family family = new Family { persons = new List<Person> { mom, dad, bro, sis } };
我想将数据序列化为这样的东西:
family: {
persons: [
{ name: "bro", pos: { x: 1, y: 5 } },
{ name: "sis", pos: { x: 2, y: 6 } },
{ name: "mom", pos: { x: 3, y: 7 }, mate: "dad", children: [ "bro", "sis" ] },
{ name: "dad", pos: { x: 4, y: 8 }, mate: "mom", children: [ "bro", "sis" ] },
]
}
在此,假设名称是唯一的,则链接仅作为名称序列化。链接也可以是“ family.persons.0”或生成的唯一ID等。
要求:
格式必须是 人类可读的 ,最好也是 人类可写的 。因此,按照优先顺序:JSON,YAML *,XML,自定义。没有二进制格式。
序列化必须支持.NET提供的所有好东西。 泛型 是必须的,包括IEnumerable <>,IDictionary <>等类型。动态类型/无类型对象是可取的。
格式 不能执行 。没有Lua,Python等脚本之类的东西。
如果生成了唯一的ID,则它们必须是稳定的(通过序列化-反序列化持久化),因为文件将被放入 版本控制系统中 。
*听说过YAML,但可悲的是,它似乎已经死了。
使用JSON.NET(很棒的库!)解决了这个问题。现在,首先将对象序列化,并在我希望它们完全指向的位置进行引用。第二,没有大量的“ $ id”和“ $
ref”字段。在我的解决方案中,对象的第一个属性用作其标识符。
我创建了两个JsonConvertor
(用于引用对象和引用对象):
interface IJsonLinkable
{
string Id { get; }
}
class JsonRefConverter : JsonConverter
{
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((IJsonLinkable)value).Id);
}
public override object ReadJson (JsonReader reader, Type type, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.String)
throw new Exception("Ref value must be a string.");
return JsonLinkedContext.GetLinkedValue(serializer, type, reader.Value.ToString());
}
public override bool CanConvert (Type type)
{
return type.IsAssignableFrom(typeof(IJsonLinkable));
}
}
class JsonRefedConverter : JsonConverter
{
public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override object ReadJson (JsonReader reader, Type type, object existingValue, JsonSerializer serializer)
{
var jo = JObject.Load(reader);
var value = JsonLinkedContext.GetLinkedValue(serializer, type, (string)jo.PropertyValues().First());
serializer.Populate(jo.CreateReader(), value);
return value;
}
public override bool CanConvert (Type type)
{
return type.IsAssignableFrom(typeof(IJsonLinkable));
}
}
和一个用于保存引用数据的上下文(每种类型都有一个字典,因此ID仅在相同类型的对象之间才是唯一的):
class JsonLinkedContext
{
private readonly IDictionary<Type, IDictionary<string, object>> links = new Dictionary<Type, IDictionary<string, object>>();
public static object GetLinkedValue (JsonSerializer serializer, Type type, string reference)
{
var context = (JsonLinkedContext)serializer.Context.Context;
IDictionary<string, object> links;
if (!context.links.TryGetValue(type, out links))
context.links[type] = links = new Dictionary<string, object>();
object value;
if (!links.TryGetValue(reference, out value))
links[reference] = value = FormatterServices.GetUninitializedObject(type);
return value;
}
}
属性上的一些属性是必需的:
[JsonObject(MemberSerialization.OptIn)]
class Family
{
[JsonProperty(ItemConverterType = typeof(JsonRefedConverter))]
public List<Person> persons;
}
[JsonObject(MemberSerialization.OptIn)]
class Person : IJsonLinkable
{
[JsonProperty]
public string name;
[JsonProperty]
public Pos pos;
[JsonProperty, JsonConverter(typeof(JsonRefConverter))]
public Person mate;
[JsonProperty(ItemConverterType = typeof(JsonRefConverter))]
public List<Person> children;
string IJsonLinkable.Id { get { return name; } }
}
[JsonObject(MemberSerialization.OptIn)]
class Pos
{
[JsonProperty]
public int x;
[JsonProperty]
public int y;
}
因此,当我使用以下代码进行序列化和反序列化时:
JsonConvert.SerializeObject(family, Formatting.Indented, new JsonSerializerSettings {
NullValueHandling = NullValueHandling.Ignore,
Context = new StreamingContext(StreamingContextStates.All, new JsonLinkedContext()),
});
JsonConvert.DeserializeObject<Family>(File.ReadAllText(@"..\..\Data\Family.json"), new JsonSerializerSettings {
Context = new StreamingContext(StreamingContextStates.All, new JsonLinkedContext()),
});
我得到这个整洁的JSON:
{
"persons": [
{
"name": "mom",
"pos": {
"x": 3,
"y": 7
},
"mate": "dad",
"children": [
"bro",
"sis"
]
},
{
"name": "dad",
"pos": {
"x": 4,
"y": 8
},
"mate": "mom",
"children": [
"bro",
"sis"
]
},
{
"name": "bro",
"pos": {
"x": 1,
"y": 5
}
},
{
"name": "sis",
"pos": {
"x": 2,
"y": 6
}
}
]
}
我在解决方案中不喜欢的是,我必须使用JObject
,即使从技术上讲它是不必要的。它可能会创建很多对象,因此加载会更慢。但是看起来这是自定义对象转换器使用最广泛的方法。无论如何,可以用来避免这种情况的方法是私有的。
问题内容: 我有一堂课 我想将下面的JSON数据反序列化到上面的类/对象中 我的想法是在JSON中是一个对象,但我只想获取(在JSON中)在反序列化期间将像在类中那样传递。 如何使用Json.NET实现该目标? 我相信我可以使用CustomJsonConverter完成它。但是我很困惑。docs中的示例仅用于,但不适用。 问题答案: 我只是使用上面在问题中提到的方法解决了我的问题。在我完整的代码下
问题内容: 我试图创建一个IContractResolver来简化WebApi项目上的安全处理。 我正在尝试: 我想基于一组动态条件来序列化某些对象/属性(例如,调用端点的用户角色)。 因此,我实现了一个自定义属性,该属性在Interface的CreateProperty重写中进行了检查,并将ShouldSerialize函数设置为我自己的逻辑。 我现在的问题是,是否可以有条件地序列化某个列表中的
问题内容: 我们正在考虑用JSON(WCF或其他)调用替换(一些或许多)“经典” SOAP XML WCF调用,因为其开销较低且易于直接在Javascript中使用。现在,我们刚刚在Web服务中添加了一个额外的Json端点,并在某些操作中添加了WebInvoke属性并对其进行了测试。使用C#.Net客户端或Javascript客户端,一切正常。到目前为止,一切都很好。 但是,似乎将大JSON字符串
easyopen序列化使用fastjson处理json,xstream处理xml。现在我们来自定义实现一个json处理: 新建一个类JsonFormatter,实现ResultSerializer接口 public class JsonFormatter implements ResultSerializer { @Override public String serialize(
例如:在pojo类中使用Date对象,将其序列化为默认格式“2016-09-27T12:11:17.430Z”。我只需要序列化它来显示日期值,去掉与时间相关的信息。
我正在开发一个API,使用ASP公开一些数据。NET Web API。 在其中一个API中,客户端希望我们以格式公开日期。我不想为此更改全局设置(例如,),因为它非常特定于此客户端。我在为多个客户开发的解决方案中做到了这一点。 我能想到的一个解决方案是创建一个自定义的,然后将其放入我需要进行自定义格式化的属性中 例如。 只是想知道是否还有其他简单的方法。