使用[JsonConverter]属性时,我的JsonConverter类中的StackOverflowException

Ary*_*rys 7 .net json.net c#-4.0

我有一个测试类,我试图序列化:

public class Testing
{
    private string _name;
    private string _firstname = "firstname";
    public string _lastname;
    private DateTime _datenow = DateTime.Now;
    public DateTime _birthdate = DateTime.Now;

    public string Name { get { return _name; } set { _name = value; } }
}
Run Code Online (Sandbox Code Playgroud)

我使用自定义JsonConverter来处理测试类的序列化:

public class TestingConverter : JsonConverter
{
    private Type[] _types = new Type[] { typeof(Testing)};

    /// <summary>
    /// Writes the JSON representation of the object.
    /// </summary>
    /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
    /// <param name="value">The value.</param>
    /// <param name="serializer">The calling serializer.</param>
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        try
        {
            JToken t = JToken.FromObject(value); //This is what i want to do
            //rest of code
        }
        catch (Exception ex)
        {
            Console.Write(ex.Message);
            throw;
        }
    }

    public override bool CanRead
    {
        get 
        { 
            return false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我通过将转换器传递给JsonSerializer对象来执行序列化,它可以正常工作:

Testing t = new Testing();
t._lastname = "USER LAST NAME";
JsonSerializer p = JsonSerializer.CreateDefault();
p.Converters.Add(new TestingConverter());

using (StreamWriter file = File.CreateText("output.json"))
using (JsonTextWriter writer = new JsonTextWriter(file))
{
    p.Serialize(writer, t);
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我用一个[JsonConverter]属性标记我的测试类:

[JsonConverter(typeof(TestingConverter))]
public class Testing
{
    private string _name;
    private string _firstname = "firstname";
    public string _lastname;
    private DateTime _datenow = DateTime.Now;
    public DateTime _birthdate = DateTime.Now;

    public string Name { get { return _name; } set { _name = value; } }
}
Run Code Online (Sandbox Code Playgroud)

和序列化像这样:

Testing t = new Testing();
t._lastname = "USER LAST NAME";
JsonSerializer p = JsonSerializer.CreateDefault();


using (StreamWriter file = File.CreateText("output.json"))
using (JsonTextWriter writer = new JsonTextWriter(file))
{
   p.Serialize(writer, t);
}
Run Code Online (Sandbox Code Playgroud)

我的TestingConverter类被调用,但它进入该JToken.FromObject(value)方法的递归循环,最后崩溃了StackOverflowException.

谁能告诉我为什么会这样?我错过了什么?

Bri*_*ers 6

将转换器的实例传递给序列化程序时,只有序列化程序的实例知道转换器.在转换器内部,当您调用JToken.FromObject(value)它时,使用不同的序列化程序实例将值转换为a JToken.该实例不了解您的转换器,因此它按预期使用Json.Net的默认序列化逻辑.一切都很好.

另一方面,如果您[JsonConverter]在某个类型上放置一个属性以指示该类型由转换器处理,那么现在所有序列化程序实例都知道您的转换器.对JToken.FromObject(value)转换器内部的调用会启动一个新的序列化程序实例; 该实例看到它应该使用您的转换器来处理此对象类型,因此它以递归方式调用您的转换器.这将重复,直到您的堆栈空间不足.

如果要使用该[JsonConverter]属性,则需要更改转换器的内部以避免递归调用链.通常这涉及手动处理该类型的所有单个属性.例如,以下版本将适用于所应用的属性:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    Testing t = (Testing)value;
    JObject jo = new JObject();
    jo.Add("name", t.Name);
    jo.Add("lastname", t._lastname);
    jo.Add("birthdate", t._birthdate);
    jo.WriteTo(writer);
}
Run Code Online (Sandbox Code Playgroud)