我用JSON.NET序列化一些我的对象,我想知道是否有一个简单的方法来替代默认json.net转换器只针对特定对象?
I'm using JSON.NET to serialize some of my objects, and i'd like to know if there is a simple way to override the default json.net converter only for a specific object?
目前我有以下类:
public class ChannelContext : IDataContext
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<INewsItem> Items { get; set; }
}
JSON.NET目前连载上述这样的:
JSON.NET currently serializes the above like:
{
"Id": 2,
"Name": "name value",
"Items": [ item_data_here ]
}
是否有可能只是为特定类这种方式,而不是对其进行格式化:
Is it possible just for that specific class to format it this way instead:
"Id_2":
{
"Name": "name value",
"Items": [ item data here ]
}
我有点新JSON.NET。我在想,如果上面有事情做与编写自定义转换器。我没能找到如何写一个,如果任何人都可以点我出去给特定信号源的任何具体的例子,我就会非常AP preciate吧。
I'm kinda new to JSON.NET.. I was wondering if the above has something to do with writing a custom converter. I wasn't able to find any concrete examples on how to write one, If anyone can point me out to a specific source, I'll really appreciate it.
我需要找到一个解决方案,这使得该特定阶级总是转换成相同的,因为上述情况下是一个更大的背景下该JSON.NET默认的转换器将只是罚款的一部分。
I need to find a solution which makes that specific class always convert the same, because the above context is a part of an even bigger context which the JSON.NET default converter converts just fine.
希望我的问题是不够清楚......
Hope my question is clear enough...
更新:
我已经找到了如何创建新的自定义转换器(通过创建一个新的类继承自JsonConverter并重写它的抽象方法),我重写了WriteJson方法如下:
I've found how to create a new custom converter (by creating a new class which inherits from JsonConverter and override it's abstract methods), I overriden the WriteJson method as follows:
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方法的对象。
This indeed does the job successfully, but... I'm intrigued if there's a way to serialize the rest of the object properties by reusing the default JsonSerializer (or converter for that matter) instead of manually "Writing" the object using the jsonwriter methods.
更新2: 我试图得到一个比较通用的解决方案,并提出了以下内容:
UPDATE 2: I'm trying to get a more generic solution and came up with the following:
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();
}
这手动添加时,转换器的串行器,这样能正常工作:
This works fine when adding the converter manually to the serializer, like this:
jsonSerializer.Converters.Add(new AssociativeArraysConverter<DefaultFieldNameResolver>());
jsonSerializer.Serialize(writer, channelContextObj);
但使用时不能正常工作[JsonConverter()]属性设置,因为在执行时会出现一个自我循环引用到我的自定义coverter的ChannelContext级以上:
But doesn't work when using the [JsonConverter()] attribute set to my custom coverter above the ChannelContext class because of a self reference loop that occurs when executing:
serializer.Serialize(writer, value)
这显然是因为我的自定义转换器现在被认为是默认的转换器类,一旦它被设置与JsonConverterAttribute,所以我得到一个inifinite循环。 我唯一能想到的,为了解决这个问题,从一个基本的,jsonconverter类继承,并调用base.serialize()方法,而不是... 但就是这样一个JsonConverter类甚至存在?
This is obviously because my custom converter is now considered the default converter for the class once it is set with the JsonConverterAttribute, so I get an inifinite loop. The only thing I can think of, in order to solve this problem is inheriting from a basic, jsonconverter class, and calling the base.serialize() method instead... But is such a JsonConverter class even exists?
非常感谢!
米奇
如果任何人的兴趣在我的解决方案:
If anyone's interested in my solution:
在序列化某些藏品,我想创造一个关联的JSON数组,而不是一个标准的JSON数组,所以我的同事客户端开发人员可以有效地达到,而不是通过他们的迭代这些领域,用自己的名字(或密钥为此事)
When serializing certain collections, I wanted to create an associative json array instead of a standard json array, so my colleague client side developer can reach those fields efficiently, using their name (or key for that matter) instead of iterating through them.
考虑以下几点:
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; }
}
响应上下文包含被写入返回给客户端,就像你可以看到整个的反应,它包括一个被称为渠道部分,而不是输出channelcontexts在一个正常的阵列,我希望能以下列方式输出:
Response context contains the whole response which is written back to the client, like you can see, it includes a section called "channels", And instead of outputting the channelcontexts in a normal array, I'd like to be able to output in the following way:
"Channels"
{
"channelNominalId1":
{
"Name": "name value1"
"Items": [ item data here ]
},
"channelNominalId2":
{
"Name": "name value2"
"Items": [ item data here ]
}
}
因为我想用上述的其他情况下为好,我可能会决定使用不同的属性作为自己的钥匙,甚至可以选择创建自己的独特的名称,它不必做任何财产,我需要某种形式的通用的解决方案,所以我写了一个泛型类被称为AssociativeArraysConverter,它继承自JsonConverter以下列方式:
Since I wanted to use the above for other contexts as well, and I might decide to use a different property as their "key", or might even choose to create my own unique name, which doesn't have to do with any property, I needed some sort of a generic solution, therefore I wrote a generic class called AssociativeArraysConverter, which inherits from JsonConverter in the following manner:
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的单一功能,它接受的集合中的每一项类,并返回基于该对象,将作为该项目的关联对象的键上的绳子。
Now all is left to do, is create a class which implements IAssociateFieldNameResolver's single function, which accepts each item in the collection, and returns a string based on that object, which will act as the item's associative object's key.
例这样的类:
public class ChannelContextFieldNameResolver : IAssociateFieldNameResolver
{
public string ResolveFieldName(object i_Object)
{
return (i_Object as ChannelContext).NominalId;
}
}