JsonConverter CanConvert不接收类型 [英] JsonConverter CanConvert does not receive type

查看:115
本文介绍了JsonConverter CanConvert不接收类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的JsonConverter,它似乎没有被正确调用.我已经创建了转换器,并将其添加到JsonSerializerSettings.Converters集合中,并在要使用[JsonConverter(typeof(SearchGeoConverter))]进行序列化的实体上标记了该属性,但是即使具有这些位置,转换器CanConvert方法也永远不会看到我尝试转换的类型.我只看过stringintJObject.

I have a custom JsonConverter, which doesn't seem to be called correctly. I have created the converter, added it to the JsonSerializerSettings.Converters collection and marked the property on the entity I am serialising with [JsonConverter(typeof(SearchGeoConverter))], but even with these in place the converters CanConvert method never sees the type I am trying to convert. I only ever see, string, int and JObject.

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

My converter looks like this:

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.使用该属性时,Json.Net假定您提供了正确的转换器,因此它不会受到CanConvert检查的困扰.如果删除该属性,则会通过将转换器实例传递给设置来调用它.您将看到Json.Net针对所有其他属性类型测试了转换器.

CanConvert does not get called when you mark something with [JsonConverter]. When you use the attribute, Json.Net assumes you have provided the correct converter, so it doesn't bother with the CanConvert check. If you remove the attribute, then it will get called by virtue of you passing the converter instance to the settings. What you are seeing is Json.Net testing your converter for all the other property types.

编辑

我整理了一个快速的小提琴以显示我的意思(为了完整性,下面也复制了代码).

I put together a quick fiddle to show what I mean (code is also reproduced below for completeness).

程序没有任何变化,CanConvert()FooConverter上被除 Foo之外的所有类型调用,但仍可以正确转换Foo.

With no changes the program, CanConvert() gets called on the FooConverter for all types except Foo, yet it still converts Foo correctly.

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

If you comment out the [JsonConverter] attribute on the Wrapper.Foo property, you can see that CanConvert() will now get called for type Foo by virtue of the FooConverter being included in the JsonSerializerSettings.

如果您改为在Main中将FooConverter添加到设置的行注释掉,则从不调用任何类型的CanConvert,但由于[JsonConverter]Foo仍可正确转换属性应用于Wrapper类中的Foo属性.

If you instead comment out the line in Main where the FooConverter is added to the settings, then CanConvert is never called for any type, yet Foo is still converted correctly due to the [JsonConverter] attribute applied to the Foo property in the Wrapper class.

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

So the takeaway here is that there are two mechanisms for indicating whether a converter should be used, and you don't need both. You can apply an attribute, and that will tell Json.Net that a particular converter should be used for a particular property (or class) and it does not need to ask the converter first. Alternatively, you can add the converter to the settings, in which case Json.Net has to ask each converter whether it can handle each type. The former is a bit more efficient, while the latter is useful in situations where you don't own the source code for the class you're trying to convert. Hope this makes sense.

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

这篇关于JsonConverter CanConvert不接收类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆