JsonConverter CanConvert 不接收类型

2024-01-06

我有一个习惯JsonConverter,这似乎没有被正确调用。我已经创建了转换器,并将其添加到JsonSerializerSettings.Converters集合并标记了我正在序列化的实体上的属性[JsonConverter(typeof(SearchGeoConverter))],但即使有了这些转换器CanConvert方法永远不会看到我试图转换的类型。我只见过,string, int and JObject.

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

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 测试您的转换器的所有其他属性类型。

EDIT

我快速整理了一个fiddle https://dotnetfiddle.net/kYblzk来展示我的意思(为了完整性,下面也复制了代码)。

在不改变程序的情况下,CanConvert()被呼叫FooConverter适用于所有类型except Foo,但它仍然转换Foo正确。

如果你注释掉[JsonConverter]属性上的Wrapper.Foo属性,你可以看到CanConvert()现在将被要求输入类型Foo凭借FooConverter被纳入其中JsonSerializerSettings.

如果您注释掉中的行Main哪里的FooConverter添加到设置中,然后CanConvert从未被任何类型调用过,但是Foo仍然可以正确转换,因为[JsonConverter]属性应用于Foo财产在Wrapper class.

因此,这里的要点是,有两种机制可以指示是否应使用转换器,但您不需要同时使用这两种机制。您可以应用一个属性,这将告诉 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();
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JsonConverter CanConvert 不接收类型 的相关文章

  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 用于检查类是否具有运算符/成员的 C++ 类型特征[重复]

    这个问题在这里已经有答案了 可能的重复 是否可以编写一个 C 模板来检查函数是否存在 https stackoverflow com questions 257288 is it possible to write a c template
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 使用 x509 证书签署 json 文档或字符串

    如何使用 x509 证书签署 json 文档或字符串 public static void fund string filePath C Users VIKAS Desktop Data xml Read the file XmlDocum
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • C++ 标准是否指定了编译器的 STL 实现细节?

    在写答案时this https stackoverflow com questions 30909296 can you put a pimpl class inside a vector我遇到了一个有趣的情况 这个问题演示了这样一种情况
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐