Mik*_* S. 31 .net c# json json.net
我正在使用JSON.NET来序列化我的一些对象,我想知道是否有一种简单的方法来覆盖特定对象的默认json.net转换器?
目前我有以下课程:
public class ChannelContext : IDataContext
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<INewsItem> Items { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
JSON.NET目前序列化如上:
{
"Id": 2,
"Name": "name value",
"Items": [ item_data_here ]
}
Run Code Online (Sandbox Code Playgroud)
是否可能只针对该特定类以这种方式格式化它:
"Id_2":
{
"Name": "name value",
"Items": [ item data here ]
}
Run Code Online (Sandbox Code Playgroud)
我是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();
}
Run Code Online (Sandbox Code Playgroud)
这确实成功地完成了工作,但是......如果有一种方法可以通过重用默认的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();
}
Run Code Online (Sandbox Code Playgroud)
将转换器手动添加到序列化程序时,这可以正常工作,如下所示:
jsonSerializer.Converters.Add(new AssociativeArraysConverter<DefaultFieldNameResolver>());
jsonSerializer.Serialize(writer, channelContextObj);
Run Code Online (Sandbox Code Playgroud)
但是当使用[JsonConverter()]属性设置为ChannelContext类上方的自定义转换器时,由于执行时发生的自引用循环,因此不起作用:
serializer.Serialize(writer, value)
Run Code Online (Sandbox Code Playgroud)
这显然是因为我的自定义转换器现在被认为是使用JsonConverterAttribute设置的类的默认转换器,所以我得到了一个无限循环.我唯一能想到的是,为了解决这个问题,我们继承了一个基本的jsonconverter类,并调用了base.serialize()方法......但是这样的JsonConverter类是否存在?
非常感谢!
米奇
Mik*_* S. 28
如果有人对我的解决方案感兴趣:
在序列化某些集合时,我想创建一个关联的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; }
}
Run Code Online (Sandbox Code Playgroud)
响应上下文包含写回客户端的整个响应,如您所见,它包含一个名为"channels"的部分,而不是在普通数组中输出channelcontexts,我希望能够输出以下方式:
"Channels"
{
"channelNominalId1":
{
"Name": "name value1"
"Items": [ item data here ]
},
"channelNominalId2":
{
"Name": "name value2"
"Items": [ item data here ]
}
}
Run Code Online (Sandbox Code Playgroud)
由于我也想将上述内容用于其他上下文,我可能决定使用不同的属性作为"密钥",或者甚至可能选择创建我自己的唯一名称,这与任何属性无关,我需要某种通用解决方案,因此我编写了一个名为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();
}
}
Run Code Online (Sandbox Code Playgroud)
并声明了以下界面:
public interface IAssociateFieldNameResolver
{
string ResolveFieldName(object i_Object);
}
Run Code Online (Sandbox Code Playgroud)
现在剩下要做的就是创建一个实现IAssociateFieldNameResolver单个函数的类,它接受集合中的每个项目,并返回一个基于该对象的字符串,该字符串将充当项目的关联对象的键.
这样一个类的例子是:
public class ChannelContextFieldNameResolver : IAssociateFieldNameResolver
{
public string ResolveFieldName(object i_Object)
{
return (i_Object as ChannelContext).NominalId;
}
}
Run Code Online (Sandbox Code Playgroud)