我有一个用jsonconverter属性修饰的类来使用我的自定义转换器。定制转换器的目的是使用一些定制逻辑序列化CustomProperty
。我决定使用JObject.FromObject
来自动序列化属性,而不是编写代码来序列化所有原始属性,然后再执行类似o.Remove("CustomProperty")
的操作,然后将自定义序列化成员添加到o
中。
但是由于类是用JsonConverter
属性修饰的,JObject.FromObject
再次调用myClassAJsonConverter
,这将导致infinte递归调用。在调用JObject.FromObject
时,是否可以特别告诉json使用它的默认转换器而不是我的自定义转换器。
[Newtonsoft.Json.JsonConverter(typeof(ClassAJsonConverter))]
public class ClassA
{
public string A {get; set;}
public int B {get; set;}
.
//20 some properties
.
public CustomProp CustomProperty {get; set;}
}
public class ClassAJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ClassA);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
.
var o = JObject.FromObject(value); //Here infinite recurrence occur
.
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
.
.
.
}
}
注意:我遇到了Recursively call JsonSerializer in a JsonConverter但无法实现它。此外,我不想添加依赖到automapper只是为了这个用途。既然这个问题已经提出一年多了,有没有人找到更好的方法来解决这个问题?
最佳答案
如果用[JsonConverter]
属性修饰了类,那么序列化程序的所有实例都会知道它。因此,如果在转换器中使用JObject.FromObject
,即使尝试向其传递新的序列化程序实例,也会进入无限递归循环。
有两种方法可以解决这个问题:
手动处理类中每个字段的序列化,而不是调用JObject.FromObject
,或者
从类声明中移除[JsonConverter]
属性,并将转换器的实例传递给序列化程序。这种方法依赖于CanConvert
的正确实现(如您的问题所示),因此转换器仅应用于预期的类。
例如:
string json = JsonConvert.SerializeObject(classA, new ClassAJsonConverter());
如果
CustomProperty
的序列化不依赖于ClassA
的其他成员,则另一种选择是为CustomProp
类而不是ClassA
创建自定义转换器。然后,您的转换器不必做技巧来担心其他属性;它只需担心CustomProp
本身。另一个可能的解决方案
我找到了一个可能对你有用的解决方案,但感觉有点老套。其思想是在
JsonSerializer
中创建一个新的JsonConverter
实例,然后在该序列化程序上使用一个特殊的ContractResolver
,该序列化程序在被要求解决当前转换器时会否认其知识。这将允许您在转换器中使用JObject.FromObject
,而不必进入递归循环,即使您的类应用了[JsonConverter]
属性。这种方法的缺点是,应用到外部序列化程序的任何其他设置都不会自动传递到内部序列化程序,因此如果需要保留这些设置,则需要手动复制它们。下面是解析程序的代码:
class JsonConverterExclusionResolver<T> : DefaultContractResolver
{
protected override JsonConverter ResolveContractConverter(Type objectType)
{
JsonConverter conv = base.ResolveContractConverter(objectType);
if (conv != null && conv.GetType() == typeof(T))
{
// if something asks for the converter we're excluding,
// we never heard of it
return null;
}
return conv;
}
}
当这个解析器就位时,您需要修改
ClassAJsonConverter
以如下方式使用它:public class ClassAJsonConverter : JsonConverter
{
private IContractResolver exclusionResolver =
new JsonConverterExclusionResolver<ClassAJsonConverter>();
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ClassA);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JsonSerializer innerSerializer = new JsonSerializer();
innerSerializer.ContractResolver = exclusionResolver;
// (copy other settings from the outer serializer if needed)
var o = JObject.FromObject(value, innerSerializer);
// ...do your custom stuff here...
o.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}