我正在使用JSON.NET序列化一些对象,并且我想知道是否有一种简单的方法可以仅针对特定对象覆盖默认json.net转换器?
目前我有以下课程:
public class ChannelContext : IDataContext { public int Id { get; set; } public string Name { get; set; } public IEnumerable<INewsItem> Items { get; set; } }
JSON.NET当前将上述序列化为:
{ "Id": 2, "Name": "name value", "Items": [ item_data_here ] }
是否可以仅通过特定方式将其格式化为:
"Id_2": { "Name": "name value", "Items": [ item data here ] }
我对JSON.NET有点陌生。我想知道上面是否与编写自定义转换器有关。我找不到任何有关如何编写示例的具体示例。如果有人可以指出我的具体信息,我将不胜感激。
我需要找到一个使特定类始终转换相同的解决方案,因为上述上下文是更大上下文的一部分,JSON.NET默认转换器可以很好地转换该上下文。
希望我的问题很清楚…
更新:
我发现了如何创建新的自定义转换器(通过创建从JsonConverter继承并覆盖其抽象方法的新类),我重写了WriteJson方法,如下所示:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { ChannelContext contextObj = value as ChannelContext; writer.WriteStartObject(); writer.WritePropertyName("id_" + contextObj.Id); writer.WriteStartObject(); writer.WritePropertyName("Name"); serializer.Serialize(writer, contextObj.Name); writer.WritePropertyName("Items"); serializer.Serialize(writer, contextObj.Items); writer.WriteEndObject(); writer.WriteEndObject(); }
这确实可以成功完成工作,但是…我很感兴趣是否有一种方法可以通过重用默认的JsonSerializer(或相应的转换器)来序列化其余对象属性,而不是使用jsonwriter手动“写入”对象方法。
更新2: 我试图获得一个更通用的解决方案,并提出了以下内容:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { writer.WriteStartObject(); // Write associative array field name writer.WritePropertyName(m_FieldNameResolver.ResolveFieldName(value)); // Remove this converter from serializer converters collection serializer.Converters.Remove(this); // Serialize the object data using the rest of the converters serializer.Serialize(writer, value); writer.WriteEndObject(); }
手动将转换器添加到序列化器时,这种方法可以正常工作,如下所示:
jsonSerializer.Converters.Add(new AssociativeArraysConverter<DefaultFieldNameResolver>()); jsonSerializer.Serialize(writer, channelContextObj);
但是在使用[JsonConverter()]属性设置为ChannelContext类上方的自定义掩体时不起作用,因为在执行时会发生自引用循环:
serializer.Serialize(writer, value)
这显然是因为自定义转换器现在被视为使用JsonConverterAttribute设置的类的默认转换器,所以我得到了无限循环。为了解决这个问题,我唯一想到的就是从一个基本的jsonconverter类继承,然后调用base.serialize()方法…但是,这样的JsonConverter类是否存在?
非常感谢!
米奇
如果有人对我的解决方案感兴趣:
在序列化某些集合时,我想创建一个关联的json数组而不是标准的json数组,因此我的同事客户端开发人员可以使用它们的名称(或相应的键)来有效地访问这些字段,而不是遍历它们。
考虑以下:
public class ResponseContext { private List<ChannelContext> m_Channels; public ResponseContext() { m_Channels = new List<ChannelContext>(); } public HeaderContext Header { get; set; } [JsonConverter( typeof(AssociativeArraysConverter<ChannelContextFieldNameResolver>))] public List<ChannelContext> Channels { get { return m_Channels; } } } [JsonObject(MemberSerialization = MemberSerialization.OptOut)] public class ChannelContext : IDataContext { [JsonIgnore] public int Id { get; set; } [JsonIgnore] public string NominalId { get; set; } public string Name { get; set; } public IEnumerable<Item> Items { get; set; } }
响应上下文包含整个响应,该响应被写回到客户端,如您所见,它包含一个称为“通道”的部分,并且我不想在常规数组中输出channelcontext,而是希望在以下方式:
"Channels" { "channelNominalId1": { "Name": "name value1" "Items": [ item data here ] }, "channelNominalId2": { "Name": "name value2" "Items": [ item data here ] } }
由于我也想将以上内容用于其他上下文,并且我可能会决定使用其他属性作为其“键”,甚至可能选择创建自己的唯一名称,而该名称与任何属性都没有关系,我需要某种通用解决方案,因此我编写了一个名为AssociativeArraysConverter的通用类,该类以以下方式从JsonConverter继承:
public class AssociativeArraysConverter<T> : JsonConverter where T : IAssociateFieldNameResolver, new() { private T m_FieldNameResolver; public AssociativeArraysConverter() { m_FieldNameResolver = new T(); } public override bool CanConvert(Type objectType) { return typeof(IEnumerable).IsAssignableFrom(objectType) && !typeof(string).IsAssignableFrom(objectType); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { IEnumerable collectionObj = value as IEnumerable; writer.WriteStartObject(); foreach (object currObj in collectionObj) { writer.WritePropertyName(m_FieldNameResolver.ResolveFieldName(currObj)); serializer.Serialize(writer, currObj); } writer.WriteEndObject(); } }
并声明以下接口:
public interface IAssociateFieldNameResolver { string ResolveFieldName(object i_Object); }
现在要做的就是创建一个类,该类实现IAssociateFieldNameResolver的单个函数,该函数接受集合中的每个项目,并返回基于该对象的字符串,该字符串将用作该项目的关联对象的键。
这样的类的示例是:
public class ChannelContextFieldNameResolver : IAssociateFieldNameResolver { public string ResolveFieldName(object i_Object) { return (i_Object as ChannelContext).NominalId; } }