本文介绍了使用默认JsonSerializer与JsonConverterAttribute装饰类时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一类装饰着JsonConverter属性使用个性化的转换器。定制转换器的目的是序列化 CustomProperty 使用一些自定义的逻辑。而不是写code序列化所有基本属性,我决定使用 JObject.FromObject 自动序列化的属性和后来做类似 o.Remove(CustomProperty),然后添加自定义序列成员 0
但由于该类装饰有 JsonConverter 属性, JObject.FromObject 再次呼吁我的 ClassAJsonConverter 这导致infinte递归调用。在调用 JObject.FromObject 的一点是可以明确告诉JSON使用它是我的自定义的默认转换器来代替。

I have a class decorated with JsonConverter attribute to use my custom converter. The aim of the custom converter is to serialize CustomProperty using some custom logic. Instead of writing code to serialize all the primitive properties, I decided to use JObject.FromObject to automatically serialize the properties and would later do something like o.Remove("CustomProperty") and then add the custom serialized member to o.
But since the class is decorated with JsonConverter attribute, JObject.FromObject again calls my ClassAJsonConverter which leads to infinte recursive call. At the point of calling JObject.FromObject is it possible to specifically tell the json to use it's default converter instead of my custom one.

[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调用JsonSerializer在JsonConverter 但无法实现它。此外,我不喜欢依赖添加到AutoMapper只为这一个用途。由于这个问题是一个多岁,有没有人找到了一个更好的办法来做到这一点?

Note: I came across Recursively call JsonSerializer in a JsonConverter but was not able to implement it. Also I would not like to add dependency to AutoMapper just for this one use. Since the question was more than a year old, has anyone found a better way to do it?

推荐答案

如果你装饰了你的类与 [JsonConverter] 属性,串行那么所有实例会知道这件事。因此,如果你使用 JObject.FromObject 转换器中,你将进入一个无限递归循环,即使你试图通过一个新的序列化实例。

If you've decorated your class with a [JsonConverter] attribute, then all instances of the serializer will know about it. Therefore if you use JObject.FromObject within the converter you will get into an infinite recursive loop, even if you try to pass it a new serializer instance.

有解决这个问题有两种方式:

There are two ways around the problem:

  1. 手工处理,而不是调用每个字段的序列化类 JObject.FromObject
  2. 从类中删除声明 [JsonConverter] 属性,而是通过转换器的实例序列化。这种方法依赖于正确实施 CanConvert 的(如你的问题),这样转换只适用于预期的类。
  1. Manually handle the serialization of each field in your class instead of calling JObject.FromObject, or
  2. Remove the [JsonConverter] attribute from the class declaration, and instead pass an instance of the converter to the serializer. This approach relies on the correct implementation of CanConvert (as shown in your question) so that the converter is applied only to the intended class.

例如:

string json = JsonConvert.SerializeObject(classA, new ClassAJsonConverter());

如果你的 CustomProperty 不依赖于 ClassA的的其他成员序列化,那么另一种选择是特别是创建一个自定义转换为 CustomProp 类代替 ClassA的。那么你的转换器不具备一些小把戏担心等性能;它只是担心 CustomProp 本身。

If the serialization of your CustomProperty does not depend on the other members of ClassA, then another alternative is to create a custom converter specifically for the CustomProp class instead of ClassA. Then your converter doesn't have to do tricks to worry about other properties; it just has to worry about CustomProp itself.

另一种可能的解决方案

我发现,可能为你工作的解决方案,但感觉有点哈克。我们的想法是建立在 JsonConverter ,然后用一个新的 JsonSerializer 例如一个特殊的 ContractResolver 上序列化时,要求解决这个问题而disavows的电流转换器的知识。这将允许您使用 JObject.FromObject 转换器内没有进入一个递归循环,甚至当你有 [JsonConverter] 属性应用到你的类。这样做的缺点做法是,你可能已经应用到外部串行任何其他设置都不会自动被抬到内部串行器,所以你需要手动复制这些设置,如果你需要保留它们。

I found a solution that might work for you, but it feels a little hacky. The idea is to create a new JsonSerializer instance inside the JsonConverter, and then use a special ContractResolver on that serializer which disavows knowledge of the current converter when asked to resolve it. This will allow you to use JObject.FromObject inside the converter without getting into a recursive loop, even while you have the [JsonConverter] attribute applied to your class. The downside to this approach is that any other settings that you may have applied to the outer serializer will not be automatically carried to the inner serializer, so you will need to manually copy those settings if you need to keep them.

下面是$ C $下的解析:

Here is the code for the resolver:

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 来使用它是这样的:

With this resolver in place, you would need to modify your ClassAJsonConverter to use it like this:

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();
    }
}

这篇关于使用默认JsonSerializer与JsonConverterAttribute装饰类时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 15:01