如何"内联"使用json.net生成json的属性

时间:2016-11-29 09:50:56

标签: c# .net json json.net

我在其中一个课程中有一个属性,我试图用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 = "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 I期待如下:

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

显然,我可以通过在ManufacturerEmail中同时使用PartNumberISteeringWheel并将一个或另一个null设置为忽略空值来实现,但我和#39; d而是在我的课程中正确分开。

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

1 个答案:

答案 0 :(得分:1)

一种方法是为ISteeringWheelIdentifier创建自己的自定义json反序列化器,您应该在其中为每个方向盘标识符类型实现所需的反序列化结果(请参阅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; }

}