【问题标题】:Run default serialization logic from JsonConverter从 JsonConverter 运行默认序列化逻辑
【发布时间】:2014-02-17 10:24:41
【问题描述】:

我有一个JsonConverter,根据特定于实例的标志,需要

  • 运行自定义序列化逻辑
  • 运行默认的 Json.NET 序列化逻辑

如何从JsonConverter 运行默认的 Json.NET 序列化逻辑?

谢谢

【问题讨论】:

标签: c# serialization json.net


【解决方案1】:

这是一个例子。假设您要序列化的类如下所示:

class Foo
{
    public bool IsSpecial { get; set; }
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
}

IsSpecial 标志用于控制我们是在转换器中做一些特殊的事情还是让事情自然地序列化。你可以这样写你的转换器:

class FooConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Foo).IsAssignableFrom(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Foo foo = (Foo)value;
        JObject jo;
        if (foo.IsSpecial)
        {
            // special serialization logic based on instance-specific flag
            jo = new JObject();
            jo.Add("names", string.Join(", ", new string[] { foo.A, foo.B, foo.C }));
        }
        else
        {
            // normal serialization
            jo = JObject.FromObject(foo);
        }
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

然后,要使用转换器,请将其实例传递给 SerializeObject 方法(例如在设置中)。 (不要用JsonConverter 属性装饰目标类,否则在序列化时会导致无限递归循环。)

class Program
{
    static void Main(string[] args)
    {
        List<Foo> foos = new List<Foo>
        {
            new Foo
            {
                A = "Moe",
                B = "Larry",
                C = "Curly",
                IsSpecial = false
            },
            new Foo
            {
                A = "Huey",
                B = "Dewey",
                C = "Louie",
                IsSpecial = true
            },
        };

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new FooConverter());
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(foos, settings);
        Console.WriteLine(json);
    }
}

输出:

[
  {
    "IsSpecial": false,
    "A": "Moe",
    "B": "Larry",
    "C": "Curly"
  },
  {
    "names": "Huey, Dewey, Louie"
  }
]

【讨论】:

  • 这很好用,除了我有需要包含在“正常”序列化过程中的自定义转换器。所以对于这个例子,FooConverter 也需要包含在序列化过程中。然后这会导致“正常”序列化再次通过FooConverter,使用IsSpecial = false。换句话说,问题在于序列化过程中遇到的字段与直接传递到JsonConvert.Serialize 的对象不同。一个(非最佳)解决方案是要求所有字段引用都使用[JsonConverter] 引用进行注释。
  • 我想我可能误解了你的问题。您能否编辑您的问题以包含您尝试序列化的类层次结构的一个简单示例(Foo、Bar 等),以及如果您的转换器以您想要的方式工作,您想要的 JSON 输出是什么?听起来您希望它的行为有所不同,具体取决于要序列化的对象是否处于根级别,而不是由对象实例上的标志控制。
  • 只要您不尝试保留参考资料,它就非常有效。但是,如果您需要 id 字段,它似乎不起作用。
  • 自定义转换器或自定义序列化程序设置可以通过将新的JsonSerializer 传入JObject.FromObject 来完成。例如:var jo = JObject.FromObject(value, JsonSerializer.CreateDefault(new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }));
【解决方案2】:

您可以更改 CanWrite 属性以禁用自定义序列化程序。如果对象可以包含相同类型的子对象或者您在多个线程中进行序列化,这将无法正常工作。

class FooConverter : JsonConverter
{
    bool _canWrite = true;
    public override bool CanWrite
    {
        get { return _canWrite;}
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Foo foo = (Foo)value;
        JObject jo;
        if (foo.IsSpecial)
        {
            // special serialization logic based on instance-specific flag
            jo = new JObject();
            jo.Add("names", string.Join(", ", new string[] { foo.A, foo.B, foo.C }));
        }
        else
        {
            // normal serialization
            _canWrite = false;
            jo = JObject.FromObject(foo);
            _canWrite = true;
        }
        jo.WriteTo(writer);
    }
}

【讨论】:

  • +1 -- 我有一个自定义合约解析器,它创建一个隐藏的 json 转换器 -- 每个都是它自己的实例,因此修改实例级别 CanReadCanWrite 以防止递归正在工作非常适合我。 -- 不过,我使用serializer.Serialize(writer, value); 写入值,我建议将值设置回finally 块中的原始值,这样它就不会陷入奇怪的状态。
猜你喜欢
  • 2015-06-19
  • 2016-06-05
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 1970-01-01
相关资源
最近更新 更多