Newtonsoft使用交叉引用

时间:2017-11-17 18:33:50

标签: c# json json.net json-deserialization

我有两个JSON文件(我无法更改格式),格式如下:

主要档案 -

[
   {
      "Name":"XYZ",
      "UnitReferenceId":1
   },
   {
      "Name":"ABC",
      "UnitReferenceId":2
   }
]

查找/引用JSON文件 -

[
   {
      "UnitReferenceId":1,
      "Units":[
         {
            "Unit":"mg",
            "Scale":1
         },
         {
            "Unit":"gm",
            "Scale":1000
         },
         {
            "Unit":"kg",
            "Scale":1000000
         }
      ]
   },
   {
      "UnitReferenceId":2,
      "Units":[
         {
            "Unit":"mm",
            "Scale":1
         },
         {
            "Unit":"m",
            "Scale":1000
         },
         {
            "Unit":"km",
            "Scale":1000000
         }
      ]
   }
]

我如何使用Newtonsoft JSON将其反序列化为C#类,如下所示:

public class Widget
{
    public string Name {get; set;}
    public UnitReference UnitReference { get; set; }
}

public class UnitReference
{
    public long UnitReferenceId { get; set; }
    public List<Unit> Units { get; set; }
}
public class Unit
{
    [JsonProperty("Unit")]
    public string UnitValue { get; set; }
    public long Scale { get; set; }
}

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

您可以通过读取两个JSON文件来执行此操作:

  1. 首先将UnitReference的查找/引用JSON文件作为List<UnitReference>读取,然后转换为Dictionary<long, UnitReference>查找表。

  2. 接下来,使用Widget Dictionary<long, UnitReference>读取主文件,该UnitReferenceId传递UnitReference查找表,并可在public class UnitReference { readonly long unitReferenceId; public UnitReference(long unitReferenceId) { this.unitReferenceId = unitReferenceId; } public long UnitReferenceId { get { return unitReferenceId; } } public List<Unit> Units { get; set; } } public class Unit { [JsonProperty("Unit")] public string UnitValue { get; set; } public long Scale { get; set; } } public class Widget { public string Name { get; set; } public UnitReference UnitReference { get; set; } } 和{{1}之间进行转换在阅读和写作过程中。

  3. 因此,您的课程将如下所示:

    UnitReferenceId

    (我唯一的修改是让public class WidgetConverter : CustomPropertyConverterBase<Widget> { readonly IDictionary<long, UnitReference> units; public WidgetConverter(IDictionary<long, UnitReference> units) { this.units = units; } protected override void ReadCustomProperties(JObject obj, Widget value, JsonSerializer serializer) { var id = (long?)obj.GetValue("UnitReferenceId", StringComparison.OrdinalIgnoreCase); if (id != null) value.UnitReference = units[id.Value]; } protected override bool ShouldSerialize(JsonProperty property, object value) { if (property.UnderlyingName == nameof(Widget.UnitReference)) return false; return base.ShouldSerialize(property, value); } protected override void WriteCustomProperties(JsonWriter writer, Widget value, JsonSerializer serializer) { if (value.UnitReference != null) { writer.WritePropertyName("UnitReferenceId"); writer.WriteValue(value.UnitReference.UnitReferenceId); } } } public abstract class CustomPropertyConverterBase<T> : JsonConverter where T : class { public override bool CanConvert(Type objectType) { return typeof(T).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var jObj = JObject.Load(reader); var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType); var value = existingValue as T ?? (T)contract.DefaultCreator(); ReadCustomProperties(jObj, value, serializer); // Populate the remaining properties. using (var subReader = jObj.CreateReader()) { serializer.Populate(subReader, value); } return value; } protected abstract void ReadCustomProperties(JObject obj, T value, JsonSerializer serializer); public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType()); writer.WriteStartObject(); foreach (var property in contract.Properties.Where(p => ShouldSerialize(p, value))) { var propertyValue = property.ValueProvider.GetValue(value); if (propertyValue == null && serializer.NullValueHandling == NullValueHandling.Ignore) continue; writer.WritePropertyName(property.PropertyName); serializer.Serialize(writer, propertyValue); } WriteCustomProperties(writer, (T)value, serializer); writer.WriteEndObject(); } protected virtual bool ShouldSerialize(JsonProperty property, object value) { return property.Readable && !property.Ignored && (property.ShouldSerialize == null || property.ShouldSerialize(value)); } protected abstract void WriteCustomProperties(JsonWriter writer, T value, JsonSerializer serializer); } 成为只读,以便它可以安全地用作字典键。)

    然后,定义以下转换器:

    var units = JsonConvert.DeserializeObject<List<UnitReference>>(unitsJsonString)
        .ToDictionary(u => u.UnitReferenceId);
    
    var settings = new JsonSerializerSettings
    {
        Converters = { new WidgetConverter(units) },
    };
    var widgets = JsonConvert.DeserializeObject<List<Widget>>(widgetsJsonString, settings);
    

    反序列化如下:

    CustomPropertyConverterBase<T>

    注意:

    • 这里我是为了演示目的从JSON字符串反序列化,但您可以直接从您的文件反序列化,如custom JsonConverter所示。

    • WidgetConverter的基类WidgetConverter自动读取和写入要(反)序列化的对象的所有属性。 UnitReference然后仅覆盖Widget属性的此行为,从而无需手动序列化Character lastChar = calculation.charAt(calculation.length()-1); 的所有剩余属性。

    示例Deserialize JSON from a file

答案 1 :(得分:0)

我使用json2csharp快速创建我的课程。如果您必须在代码中实现它,请参阅JSON C# Class Generator Project