如何使用 json.net 在生成的 json 中“内联”属性

2024-05-10

我的一个类中有一个属性,我试图用 json.net 序列化它,我想“内联”,这意味着,我不想将该属性嵌套到具有属性名称的元素中,但其内容直接位于其父级中。

这是一个例子,假设我有以下类结构:

public interface ISteeringWheelIdentifier {}

public interface ISteeringWheel 
{
    ISteeringWheelIdentifier Identifier {get;}
}

public class ManufacturerIdentifier : ISteeringWheelIdentifier
{
    public string ManufacturerEmail {get; set;}
}

public class PartNumberIdentifier : ISteeringWheelIdentifier
{
    public string PartNumber {get; set;}
}

public class ClassicSteeringWheel : ISteeringWheel 
{
    public ClassicSteeringWheel(ManufacturerIdentifier identifier)
    {
        Identifier = identifier;
    }

    public string HornButtonManufacturer {get; set;}

    public ISteeringWheelIdentifier Identifier {get;private set;}
}

public class ModernSteeringWheel : ISteeringWheel
{
    public ModernSteeringWheel(PartNumberIdentifier identifier)
    {
        Identifier = identifier;
    }

    public string TouchpadManufacturer {get; set;}

    public ISteeringWheelIdentifier Identifier {get;private set;}
}

public class Car 
{
    public string CarBrand {get; set;}
    public ISteeringWheel SteeringWheel {get; set;}

}

如果我尝试使用以下代码序列化两个测试对象:

public static void Main()
{
    var car1 = new Car{CarBrand="Ford", SteeringWheel = new ModernSteeringWheel(new PartNumberIdentifier{PartNumber = "123456"})};
    var json = JsonConvert.SerializeObject(car1, Formatting.Indented);
    Console.WriteLine(json);

    var car2 = new Car{CarBrand="Toyota", SteeringWheel = new ClassicSteeringWheel(new ManufacturerIdentifier{ManufacturerEmail = "[email protected] /cdn-cgi/l/email-protection"})};
    json = JsonConvert.SerializeObject(car2, Formatting.Indented);
    Console.WriteLine(json);
}

你得到这个结果:

{
  "CarBrand": "Ford",
  "SteeringWheel": {
    "TouchpadManufacturer": null,
    "Identifier": {
      "PartNumber": "123456"
    }
  }
}
{
  "CarBrand": "Toyota",
  "SteeringWheel": {
    "HornButtonManufacturer": null,
    "Identifier": {
      "ManufacturerEmail": "[email protected] /cdn-cgi/l/email-protection"
    }
  }
}

但是,就我而言,标识符只是管理方向盘识别的不同方式的一种方法,我不需要拥有该属性。我期望得到的 Json 如下:

{
  "CarBrand": "Ford",
  "SteeringWheel": {
    "TouchpadManufacturer": null
    "PartNumber": "123456"
  }
}
{
  "CarBrand": "Toyota",
  "SteeringWheel": {
    "HornButtonManufacturer": null,
    "ManufacturerEmail": "[email protected] /cdn-cgi/l/email-protection"
  }
}

显然,我可以通过两者来做到这一点ManufacturerEmail and PartNumber in the ISteeringWheel并把其中之一null并设置忽略空值,但我宁愿在我的类中正确分隔事物。

我在这里用上面的代码创建了一个小提琴:https://dotnetfiddle.net/C9RPy9 https://dotnetfiddle.net/C9RPy9


一种方法是为 ISteeeringWheelIdentifier 创建您自己的自定义 json 反序列化器,其中您应该为每个方向盘标识符类型实现所需的反序列化结果(请参阅http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm)为例。然后,您应该为 Identifier 属性设置一个 JsonConverter 属性 [JsonConverter(typeof([您的新转换器的名称]))],并且它将按照您指定的方式反序列化。

编辑 - 当实际实现它时,事实证明要获得所需的行为有点棘手。您需要创建的转换器是 ISteeringWheel 接口的转换器。在其中,检查所有属性,直到到达标识符属性,并处理其序列化。举个例子:

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        JObject jo = new JObject();
        Type type = value.GetType();

        foreach (var prop in type.GetProperties())
        {
            if (prop.CanRead)
            {
                var propVal = prop.GetValue(value, null);
                if (prop.Name == "Identifier")
                {
                    // Iterate over all properties of the identifier, but don't add the identifier object itself 
                    // to the serialized result.
                    Type identifierType = propVal.GetType();
                    foreach (var identifierProp in identifierType.GetProperties())
                    {
                        var identifierPropVal = identifierProp.GetValue(propVal, null);
                        jo.Add(identifierProp.Name, identifierPropVal != null ? JToken.FromObject(identifierPropVal, serializer) : null);
                    }
                }
                else
                {
                    // Add the property to the serialized result
                    jo.Add(prop.Name, propVal != null ? JToken.FromObject(propVal, serializer) : null);
                }
            }
        }

        jo.WriteTo(writer);
    }

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

    public override bool CanRead
    {
        get { return false; }
    }
}

现在剩下的就是将该属性添加到汽车类中:

public class Car
{
    public string CarBrand { get; set; }

    [JsonConverter(typeof(SteeringWheelJsonConverter))]
    public ISteeringWheel SteeringWheel { get; set; }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 json.net 在生成的 json 中“内联”属性 的相关文章

  • Twitch API - 无法使用 PHP 获取身份验证令牌

    stackoverflow 的成员们大家好 我不是一个喜欢寻求帮助的人 但在这种情况下 我认为这是解决我的问题的唯一方法 谷歌并没有给我太大帮助 所以 我的问题 我想使用 Twitch API 获取一些数据 听起来很容易 我希望是这样 下面
  • 检测到堆栈崩溃

    我正在执行我的 a out 文件 执行后 程序运行一段时间 然后退出并显示消息 stack smashing detected a out terminated Backtrace lib tls i686 cmov libc so 6 f
  • C# 5 async/await 线程机制感觉不对?

    为什么让调用线程进入异步方法直到内部 等待 一旦调用异步方法就生成一个线程 这不是更干净吗 这样您就可以确定异步方法会立即返回 您不必担心在异步方法的早期阶段没有做任何昂贵的事情 我倾向于知道某个方法是否要在 我的 线程上执行代码 不管是堵
  • 为什么'enable_if'不能用于禁用这里声明

    include
  • 一元 +/- 运算符如何可能导致“-a”或“+a”中的整数提升,“a”是算术数据类型常量/变量?

    这句看似微不足道的台词摘自我的迈克 巴纳汉和布雷迪的 C 书 第 2 8 8 2 节 http publications gbdirect co uk c book chapter2 expressions and arithmetic h
  • 访问 ascx 文件中的母版页控件

    我有一个母版页文件 其中包含 2 个面板控件中的 2 个菜单 我还使用控件来检查用户是否登录并获取用户类型 根据我想要显示 隐藏面板的类型 控件本身不在母版页中引用 而是通过 CMS 系统动态引用 我想在用户控件中使用findcontrol
  • C# 编译器不会优化不必要的强制转换

    前几天 在写答案的时候这个问题 https stackoverflow com questions 2208315 why is any slower than contains在这里 关于溢出 我对 C 编译器感到有点惊讶 它没有按照我的
  • 将接口转换为其具体实现对象,反之亦然?

    在 C 中 当我有一个接口和几个具体实现时 我可以将接口强制转换为具体类型 还是将具体类型强制转换为接口 这种情况下的规则是什么 Java 和 C 中都允许这两个方向 向下转型需要显式转型 如果对象类型不正确 可能会抛出异常 然而 向上转换
  • 如何对 NServiceBus.Configure.WithWeb() 进行单元测试?

    我正在构建一个 WCF 服务 该服务接收外部 IP 上的请求并将其转换为通过 NServiceBus 发送的消息 我的单元测试之一调用Global Application Start 它执行应用程序的配置 然后尝试将 Web 服务解析为 验
  • C#6 中的长字符串插值行

    我发现 虽然字符串插值在应用于现有代码库的字符串 Format 调用时非常好 但考虑到通常首选的列限制 字符串对于单行来说很快就会变得太长 特别是当被插值的表达式很复杂时 使用格式字符串 您将获得一个可以拆分为多行的变量列表 var str
  • 如何从 Rx Subscribe 回调异步函数?

    我想回调 Rx 订阅中的异步函数 例如 像那样 public class Consumer private readonly Service service new Service public ReplaySubject
  • ASP.NET MVC 路由:如何从 URL 中省略“索引”

    我有一个名为 StuffController 的控制器 具有无参数索引操作 我希望从表单中的 URL 调用此操作mysite com stuff 我的控制器定义为 public class StuffController BaseContr
  • 逆向工程 ASP.NET Web 应用程序

    我有一个 ASP NET Web 应用程序 我没有源代码 该 bin 包含 10 个程序集和一个 compiled 文件 我在 App Code dll 上使用 Reflector 它向我显示了类和命名空间之类的东西 但它太混乱了 有没有什
  • 选择查询不适用于使用Parameters.AddWithValue 的参数

    C 中的以下查询不起作用 但我看不出问题所在 string Getquery select from user tbl where emp id emp id and birthdate birthdate cmdR Parameters
  • 如何调试 .NET 运行时中的内部错误?

    我正在尝试调试一些处理大文件的工作 代码本身works 但 NET 运行时本身会报告零星错误 对于上下文 这里的处理是一个 1 5GB 文件 仅加载到内存中一次 在循环中处理和释放 故意尝试重现此否则不可预测的错误 我的测试片段基本上是 t
  • eventSources 到事件 Json,完整日历

    我正在尝试从 eventSources 获取 json 调用到我的事件 我在 eventSources 中返回的 json 是 title Title Test start 1305841052 当我将此字符串传递到事件中时 它会正确显示日
  • 来自 3rd 方库的链接器错误 LNK2019

    我正在将旧的 vc 6 0 应用程序移植到 vs2005 我收到以下链接器错误 我花了几天时间试图找到解决方案 错误LNK2019 无法解析的外部符号 imp 创建AwnService 52 在函数 public int thiscall
  • DataContractSerializer 事件/委托字段问题

    在我的 WPF 应用程序中 我正在使用DataContractSerializer序列化对象 我发现它无法序列化具有事件或委托声明的类型 考虑以下失败的代码 Serializable public abstract class BaseCl
  • 为什么匹配模板类上的部分类模板特化与没有模板匹配的另一个部分特化不明确?

    这个问题可能很难用标题中的句子来描述 但这里有一个最小的例子 include
  • jQuery appendTo(), json 在 IE 6,7,8 中不起作用

    我这两天绞尽脑汁想找到解决办法 我使用 jQuery ajax 从数据库中获取值 以便在另一个框发生更改时更新一个框 php 脚本从数据库中获取值 然后输出 json 它在 FF 中工作正常 但在所有版本的 IE 中 选择框都不会更新 我已

随机推荐