如何将 class 序列化为 JSON,其中 属性 的类型为 Windows.Data.Json.JsonObject?

How to serialize class to JSON, where property is of type Windows.Data.Json.JsonObject?

考虑以下 class:

public class ImageDataModel
{
    public JsonObject CaptureResultData { get; }
    public SmartphoneCommand SmartphoneCommand { get; }
    public LightStageCommand LightStageCommand { get; }

    public string TimeStamp { get; }

    public ImageDataModel(string _captureResultData, LightStageCommand _lightStageCommand, SmartphoneCommand _smartphoneCommand)
    {
        CaptureResultData = JsonObject.Parse(_captureResultData);
        SmartphoneCommand = _smartphoneCommand;
        LightStageCommand = _lightStageCommand;
        TimeStamp = DateTime.Now.ToString("HH:mm.ss, dd. MM. yyyy");
    }
}

SmartphoneCommandLightStageCommand 是可序列化的对象,这些没有问题。但是,在构造函数中,_captureResultData 已经是 JsonObject 类型的序列化 JSON 字符串。由于我希望此字符串中的数据显示为序列化对象数据,而不是我的 JSON 文件中的单个字符串,因此我将其设为 JsonObject.

问题是,序列化后,CaptureResult 数据在 JSON 文件中显示如下:

  "CaptureResultData": {
    "android.control.afMode": {
      "ValueType": 2
    },
    "android.colorCorrection.gains": {
      "ValueType": 3
    },
    "android.control.awbMode": {
      "ValueType": 2
    },
    "android.lens.focalLength": {
      "ValueType": 2
    },
    "android.lens.focusDistance": {
      "ValueType": 2
    },
    "android.control.aeMode": {
      "ValueType": 2
    },
    "android.colorCorrection.mode": {
      "ValueType": 2
    },
    "android.colorCorrection.transform": {
      "ValueType": 3
    },
    "android.lens.aperture": {
      "ValueType": 2
    },
    "android.sensor.sensitivity": {
      "ValueType": 2
    },
    "android.sensor.exposureTime": {
      "ValueType": 2
    }
  },

原始字符串包含正确的数据。如何强制序列化显示实际数据,而不是 ValueType?

为了完整起见,下面是序列化的完成方式:

using (StreamWriter jsonFile = File.CreateText(uniqueFilePaths[2]))
{
    JsonSerializer serializer = new JsonSerializer
    {
        Formatting = Formatting.Indented,
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    };

    serializer.Serialize(jsonFile, new ImageDataModel(captureResultString, lightStageCommand, cameraCommand));
}
如果您直接使用 类 中的类型,

Json.NET 不支持 Windows.Data.Json namespace, so you will need to create a custom JsonConverter for JsonObject as well as JsonArray and JsonValue 中的类型。以下应该完成这项工作:

public class WindowsDataJsonObjectConverter : WindowsDataJsonConverterBase<Windows.Data.Json.JsonObject>
{
    public override JsonObject ReadJson(JsonReader reader, Type objectType, JsonObject existingValue, bool hasExistingValue, JsonSerializer serializer) =>
        JsonObject.Parse(reader.ReadOuterJson(dateParseHandling: DateParseHandling.None));
}

public class WindowsDataJsonArrayConverter : WindowsDataJsonConverterBase<Windows.Data.Json.JsonArray>
{
    public override JsonArray ReadJson(JsonReader reader, Type objectType, JsonArray existingValue, bool hasExistingValue, JsonSerializer serializer) =>
        JsonArray.Parse(reader.ReadOuterJson(dateParseHandling: DateParseHandling.None));
}

public class WindowsDataJsonValueConverter : WindowsDataJsonConverterBase<Windows.Data.Json.JsonValue>
{
    public override JsonValue ReadJson(JsonReader reader, Type objectType, JsonValue existingValue, bool hasExistingValue, JsonSerializer serializer) =>
        JsonValue.Parse(reader.ReadOuterJson(dateParseHandling: DateParseHandling.None));
}

public abstract class WindowsDataJsonConverterBase<TJsonValue> : JsonConverter<TJsonValue> where TJsonValue : IJsonValue
{
    public override void WriteJson(JsonWriter writer, TJsonValue value, JsonSerializer serializer) => 
        writer.WriteRawValue(value.Stringify());
}

public static partial class JsonExtensions
{
    // Taken from this answer 
    // To 
    public static string ReadOuterJson(this JsonReader reader, Formatting formatting = Formatting.None, DateParseHandling? dateParseHandling = null, FloatParseHandling? floatParseHandling = null)
    {
        var oldDateParseHandling = reader.DateParseHandling;
        var oldFloatParseHandling = reader.FloatParseHandling;
        try
        {
            if (dateParseHandling != null)
                reader.DateParseHandling = dateParseHandling.Value;
            if (floatParseHandling != null)
                reader.FloatParseHandling = floatParseHandling.Value;
            using (var sw = new StringWriter(CultureInfo.InvariantCulture))
            using (var jsonWriter = new JsonTextWriter(sw) { Formatting = formatting })
            {
                jsonWriter.WriteToken(reader);
                return sw.ToString();
            }
        }
        finally
        {
            reader.DateParseHandling = oldDateParseHandling;
            reader.FloatParseHandling = oldFloatParseHandling;
        }
    }
}

备注:

  • JsonObject 实现了 IDictionary<String,IJsonValue>JsonArray 实现了几个 IEnumerable 接口,因此 Json.NET 将知道如何序列化这些类型。但是,它不会知道通过调用适当的静态 Parse() 方法来反序列化它们。

  • 没有标准接口指示应使用其“原始”ToString() 值将 c# 类型序列化为 JSON,因此 Json.NET 没有知道如何序列化或反序列化 JsonValue.

    的方法
  • 或者,您可以考虑将模型中的 JsonObject 替换为 Json.NET 的 JObject。如果这样做,Json.NET 将能够在不进行任何转换的情况下对其进行序列化。

    作为第二种选择,您可以在数据模型中将 _captureResultData 保留为 string,并将 属性 标记为 [JsonConverter(typeof(RawConverter))],其中 RawConverter来自 to .

  • 因为 ImageDataModel 是不可变的,如果你想用 Json.NET 反序列化它,你需要创建一个兼容的构造函数并用 JsonConstructorAttribute 标记它:

     [JsonConstructor]
     ImageDataModel(JsonObject captureResultData, LightStageCommand lightStageCommand, SmartphoneCommand smartphoneCommand, string timeStamp)
     {
         this.CaptureResultData = captureResultData;
         this.SmartphoneCommand = smartphoneCommand;
         this.LightStageCommand = lightStageCommand;
         this.TimeStamp = timeStamp;
     }
    

    Json.NET 将使用大小写不变的名称匹配将 JSON 属性与构造函数参数匹配。

模型 fiddle here.