如何“内联"使用json.net生成的json中的属性 [英] How to "inline" a property in resulting json with json.net

查看:87
本文介绍了如何“内联"使用json.net生成的json中的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要在其中一个类中尝试通过json.net进行序列化的属性是我想要内联"的,这意味着,我不想将该属性嵌套在带有属性名称,但其内容直接位于其父项之内.

I have a property in one of my classes that I'm trying to serialize with json.net that I would like to "inline", meaning, I don't want to have the property be nested into an element with the property name, but its content be directly within its parent.

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

Here's an example, let say I have the following class structure:

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

}

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

If I try to serialize two test objects using the following code:

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 = "test@demo.com"})};
    json = JsonConvert.SerializeObject(car2, Formatting.Indented);
    Console.WriteLine(json);
}

您得到以下结果:

{
  "CarBrand": "Ford",
  "SteeringWheel": {
    "TouchpadManufacturer": null,
    "Identifier": {
      "PartNumber": "123456"
    }
  }
}
{
  "CarBrand": "Toyota",
  "SteeringWheel": {
    "HornButtonManufacturer": null,
    "Identifier": {
      "ManufacturerEmail": "test@demo.com"
    }
  }
}

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

But, for my case, the Identifier is just a way to manage the different ways that steering wheels can be identified, and I don't need to have that property. The resulting Json I'm expecting would be the following:

{
  "CarBrand": "Ford",
  "SteeringWheel": {
    "TouchpadManufacturer": null
    "PartNumber": "123456"
  }
}
{
  "CarBrand": "Toyota",
  "SteeringWheel": {
    "HornButtonManufacturer": null,
    "ManufacturerEmail": "test@demo.com"
  }
}

很明显,我可以通过在ISteeringWheel中同时包含ManufacturerEmailPartNumber并放置一个或另一个null并设置为忽略空值来做到这一点,但我宁愿将它们正确分开我的课程.

Obviously, I could do it by having both ManufacturerEmail and PartNumber in the ISteeringWheel and putting one or the other null and setting to ignore null values, but I'd rather keep things correctly separated in my classes.

我已经使用上面的代码创建了一个小提琴: https://dotnetfiddle.net/C9RPy9

I've created a fiddle with the working above code here: https://dotnetfiddle.net/C9RPy9

推荐答案

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

One approach is to create your own custom json deserializer for ISteeringWheelIdentifier, in which you should implement the desired deserialization result for each steering wheel identifier type (see http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) for an example. Then you should set an JsonConverter attribute for your Identifier property [JsonConverter(typeof([Name of your new converter]))] and it will be deserialized however you specified.

编辑-实际实现它时,要获得所需的行为会有些技巧.您需要创建的转换器是ISteeringWheel界面的转换器.在其中,遍历所有属性,直到获得标识符属性,然后处理其序列化.举个例子:

EDIT - when actually implementing it, turns out it's a bit tricker to get the desired behavior. The converter you need to create is one for the ISteeringWheel interface. In it, go over all the properties until you get to the identifier property, and handle its serialization. To the example:

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

现在剩下的就是将属性添加到car类:

Now all that remains is to add the attribute to the car class:

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

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

}

这篇关于如何“内联"使用json.net生成的json中的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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