JsonConverter CanConvert不接收类型

时间:2014-09-24 11:46:44

标签: c# json.net

我有一个自定义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();
    }
}

我错过了什么?

1 个答案:

答案 0 :(得分:14)

使用CanConvert标记内容时,

[JsonConverter]不会被调用。当您使用该属性时,Json.Net假定您提供了正确的转换器,因此它不会对CanConvert检查感到烦恼。如果删除该属性,则会通过将转换器实例传递给设置来调用它。您所看到的是Json.Net针对所有其他属性类型测试您的转换器。

修改

我快速组合fiddle来表明我的意思(代码也在下面转载完整性)。

如果没有对程序进行任何更改,CanConvert()会针对除 FooConverter之外的所有类型调用Foo,但它仍会正确转换Foo

如果您在[JsonConverter]属性上注释掉Wrapper.Foo属性,则可以看到CanConvert()现在将因类型Foo而被调用FooConverter被包含在JsonSerializerSettings

如果您注释掉MainFooConverter添加到设置中的行,则永远不会为任何类型调用CanConvert,但Foo仍然是[JsonConverter]由于Foo属性应用于Wrapper类中的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(); } } } 属性而正确转换。

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

{{1}}