JsonConverter CanConvert未接收类型



我有一个自定义的JsonConverter,它似乎没有被正确调用。我已经创建了转换器,将其添加到JsonSerializerSettings.Converters集合,并标记了与[JsonConverter(typeof(SearchGeoConverter))]串行的实体上的属性,但即使有了这些转换器,CanConvert方法也永远看不到我试图转换的类型。我只见过stringintJObject

我的转换器看起来像这样:

public class SearchGeoConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(DbGeography).IsAssignableFrom(objectType);
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var point = (DbGeography) value;
        var rawJson = string.Format("{{ "type": "Point", "coordinates": [{0}, {1}] }}", point.Latitude, point.Longitude);
        writer.WriteRaw(rawJson);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

我错过了什么?

CanConvert在用[JsonConverter]标记某个内容时不会被调用。当您使用该属性时,Json.Net假设您已经提供了正确的转换器,因此它不需要进行CanConvert检查。如果删除该属性,那么它将通过将转换器实例传递给设置而被调用。您看到的是Json.Net正在测试您的转换器的所有其他属性类型。

编辑

我整理了一个快速的小提琴来展示我的意思(为了完整起见,下面也转载了代码)。

在不更改程序的情况下,CanConvert()FooConverter上被调用,用于除Foo之外的所有类型,但它仍然正确地转换Foo

如果注释掉Wrapper.Foo属性上的[JsonConverter]属性,您可以看到,由于JsonSerializerSettings中包含FooConverterCanConvert()现在将被调用为类型Foo

如果您注释掉MainFooConverter添加到设置中的行,则CanConvert永远不会为任何类型调用,但由于Wrapper类中Foo属性应用了[JsonConverter]属性,因此Foo仍然可以正确转换。

因此,这里的要点是,有两种机制可以指示是否应该使用转换器,而不需要两者。您可以应用一个属性,这将告诉Json.Net,特定的转换器应该用于特定的属性(或类),它不需要首先询问转换器。或者,您可以将转换器添加到设置中,在这种情况下,Json.Net必须询问每个转换器是否可以处理每种类型。前者效率更高,而后者在您不拥有要转换的类的源代码的情况下很有用。希望这是有道理的。

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
public class Program
{
    public static void Main()
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        // Comment out the following line and CanConvert() never gets called on 
        // FooConverter for any type yet the FooConverter is still working due
        // to the JsonConverter attribute applied to Wrapper.Foo
        settings.Converters.Add(new FooConverter());
        settings.Converters.Add(new BarConverter());
        settings.Formatting = Formatting.Indented;
        Wrapper w = new Wrapper
        {
            Foo = new Foo
            {
                A = "bada",
                B = "boom",
            },
            Bar = new Bar
            {
                C = "bada",
                D = "bing"
            }
        };
        string json = JsonConvert.SerializeObject(w, settings);
        Console.WriteLine(json);
    }
    class Wrapper
    {
        // Comment out this attribute and CanConvert will be called on FooConverter
        // for type Foo due to the fact that the FooConverter has been added to the
        // JsonSerializerSettings
        [JsonConverter(typeof(FooConverter))]
        public Foo Foo { get; set; }
        public Bar Bar { get; set; }
    }
    class Foo
    {
        public string A { get; set; }
        public string B { get; set; }
    }
    class Bar
    {
        public string C { get; set; }
        public string D { get; set; }
    }
    class FooConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            bool result = typeof(Foo).IsAssignableFrom(objectType);
            Console.WriteLine("FooConverter CanConvert() called for type " +
                              objectType.Name + " (result = " + result + ")");
            return result;
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var foo = (Foo) value;
            JObject jo = new JObject();
            jo.Add("AplusB", new JValue(foo.A + " " + foo.B));
            jo.WriteTo(writer);
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    class BarConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            bool result = typeof(Bar).IsAssignableFrom(objectType);
            Console.WriteLine("BarConverter CanConvert() called for type " + 
                              objectType.Name + " (result = " + result + ")");
            return result;
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var bar = (Bar) value;
            JObject jo = new JObject();
            jo.Add("CplusD", new JValue(bar.C + " " + bar.D));
            jo.WriteTo(writer);
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
}

相关内容

  • 没有找到相关文章

最新更新