提问人:Foxhunt 提问时间:11/7/2023 最后编辑:dbcFoxhunt 更新时间:11/8/2023 访问量:130
System.Text.Json 序列化对象
System.Text.Json Serialize an Object
问:
我正在尝试通过 SignalR 发送对象。 它看起来像
[Serializable]
public class MyDataClass
{
//Some property correctly serialized and deserialized
public Int32 Format { get; set; }
public required Object? Value { get; set;}
}
Value 可以是 bool、string 、int ...,并由 Format 描述。
它序列化得很好。
但是当我反序列化时,我有一个,打印它时,它看起来像“ValueKind ({})”System.Text.Json.JsonElement
编辑:使用自定义 JsonConverter
使用建议的文档,我编写了一个简单的 JsonConverter 来处理这个问题:
public class MyDataClassConverter : JsonConverter<MyDataClass>
{
public override ViewModelExecutionVariable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var myData = new MyDataClass();
var properties = typeof(MyDataClass).GetProperties(BindingFlags.Instance | BindingFlags.Public);
using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
{
foreach (var propertyInfo in properties)
{
if (doc.RootElement.TryGetProperty(propertyInfo.Name, out var jsonElement))
{
object? value = JsonSerializer.Deserialize(jsonElement.GetRawText(), propertyInfo.PropertyType, options);
propertyInfo.SetValue(myData , value);
}
}
}
myData.Value = FormatHelper.GetObjectValue(myData.Format, ((JsonElement)myData.Value).GetString())!;
return myData;
}
public override void Write(Utf8JsonWriter writer, MyDataClass value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}
}
并添加了装饰器 JsonConverter(typeof(MyDataClassConverter))]
但是现在我在序列化项目列表时遇到了一个问题:
List<MyDataList> myDataList = this.GetDataList();
var json = System.Text.Json.JsonSerializer.Serialize(myDataList);
在最后一行之后,程序永远不会结束。
它在没有装饰器的情况下工作正常,不使用自定义序列化程序:
System.Text.Json.JsonSerializer.Serialize(myDataList)
然后是自定义解串程序
System.Text.Json.JsonSerializer.Deserialize<List<MyDataClass>>(message, new JsonSerializerOptions {Converters = { new MyDataClassConverter()}})!)
但它比装饰器重得多,所以我会接受任何建议来制作 Serialize 作品。
为了增加精度,FormatHelper.GetObjectValue() 是一个很大的开关:
public static Object? GetObjectValue(Int32 formatType, String? value)
{
Object? result = null;
switch (formatType)
{
case FormatTypeBase.Boolean:
result = value == "1" || value == "True";
break;
case FormatTypeBase.Numeric:
result = Double.Parse(value, CultureInfo.InvariantCulture);
break;
case FormatTypeBase.String:
result = value;
break;
//...
}
return result
}
答:
1赞
dbc
11/8/2023
#1
您的转换器基本上只是使用第二个属性()的值对一个属性(特别是)进行后处理。这可以通过实现 IJsonOnDeserialized
反序列化回调来最容易地完成:MyDataClass.Value
Format
public class MyDataClass : IJsonOnDeserialized
{
//Some properties correctly serialized and deserialized
//The Value I need to deserialize to the correct type, and its format.
public Int32 Format { get; set; } // Shouldn't this be a FormatTypeBase enum rather than an integer?
public required Object? Value { get; set;}
// A callback to convert the deserialized JsonElement to the correct primitive.
void IJsonOnDeserialized.OnDeserialized()
{
if (Value is JsonElement e)
{
Value = FormatHelper.GetObjectValue(Format, e.ValueKind == JsonValueKind.String ? e.GetString() : e.GetRawText());
}
}
}
public enum FormatTypeBase
{
Boolean = 1,
Numeric = 2,
String = 3,
}
public class FormatHelper
{
public static Object? GetObjectValue(Int32 formatType, String? value)
{
if (value == null)
return null; // Or throw an exception?
Object? result = null;
switch ((FormatTypeBase)formatType)
{
case FormatTypeBase.Boolean:
result = value == "1" || value.Equals("true", StringComparison.OrdinalIgnoreCase); // TODO: check for invalid non-Boolean string values.
break;
case FormatTypeBase.Numeric:
result = Double.Parse(value, CultureInfo.InvariantCulture);
break;
case FormatTypeBase.String:
result = value;
break;
//...
default:
throw new NotImplementedException(((FormatTypeBase)formatType).ToString());
}
return result;
}
}
以这种方式执行操作完全消除了在序列化期间编写回退到默认逻辑的需要。虽然有点棘手,但这是可能的 - 尽管如果您将转换器直接应用于类型,则不会。有关详细信息,请参阅如何在自定义 System.Text.Json JsonConverter 中使用默认序列化?的答案。JsonConverter
在这里演示小提琴。
评论
Value
ObjectAsPrimitiveConverter
FormatHelper.GetObjectValue()
System.Text.Json.JsonSerializer.Deserialize<List<MyDataClass>>(message, new JsonSerializerOptions {Converters = { new MyDataClassConverter()}})!)