使用
JsonSerialize.DeserializeAsync
和自定义转换器进行反序列化,例如
public class MyStringJsonConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.GetString();
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
在这里我会得到 all
string
属性,这还可以,不过有没有办法检查给定值的属性名称,例如像这样的东西,在哪里只处理 Body
属性:
class MyMailContent
{
public string Name { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
public class MyStringJsonConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.PropertyName.Equals("Body"))
{
var s = reader.GetString();
//do some process with the string value
return s;
}
return reader.GetString();
}
}
或者还有其他方法来挑选给定的属性吗?
注意,我正在寻找使用
System.Text.Json
的解决方案。
感谢Jimi的评论,并在他的批准下,我使用他建议的解决方案发布了一个维基答案,任何有更多贡献的人,请随时这样做。
在大多数情况下,接受的答案是一个好的答案,但如果仍然需要通过属性名称处理一个或多个特定属性,这里是一种方法。
public class MyMailContent
{
public string Name { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
public class MyMailContentJsonConverter : JsonConverter<MyMailContent>
{
public override MyMailContent Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
var mailContent = new MyMailContent();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return mailContent;
}
if (reader.TokenType == JsonTokenType.PropertyName)
{
var propertyName = reader.GetString();
reader.Read();
switch (propertyName)
{
case "Name":
mailContent.Name = reader.GetString();
break;
case "Subject":
mailContent.Subject = reader.GetString();
break;
case "Body":
string body = reader.GetString();
//do some process on body here
mailContent.Body = body;
break;
}
}
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, MyMailContent mailcontent, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
private static JsonSerializerOptions _jsonDeserializeOptions = new()
{
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
Converters =
{
new MyMailContentJsonConverter()
}
};
然后像这样使用它
var jsonstring = JsonSerializer.Serialize(new MyMailContent
{
Name = "some name",
Subject = "some subject",
Body = "some body"
});
var MailContent = JsonSerializer.Deserialize<MyMailContent>(jsonstring, _jsonDeserializeOptions);
System.Text.Json 不会在 JsonConverter<T>.Read()
中提供父属性名称,或者更一般地说,当前值的
路径。此信息在内部跟踪 - 它位于
ReadStack.JsonPath()
中 - 但 ReadStack
是内部的,从未传递给应用程序代码。
但是,如注册示例 - 属性上的 [JsonConverter] 中所述,您可以使用
MyStringJsonConverter
将 public string Body { get; set; }
直接应用于
JsonConverterAttribute
:
class MyMailContent
{
public string Name { get; set; }
public string Subject { get; set; }
[JsonConverter(typeof(MyStringJsonConverter))]
public string Body { get; set; }
}
通过这样做,
MyStringJsonConverter.Read()
和.Write()
将仅在MyMailContent.Body
时触发。即使您在 JsonConverter<string>
中有一些整体
JsonSerializerOptions.Converters
,应用于该属性的转换器也会 优先:
在序列化或反序列化期间,按以下顺序为每个 JSON 元素选择转换器,从最高优先级到最低优先级列出:
应用于属性。[JsonConverter]
- 转换器已添加到
集合中。Converters
应用于自定义值类型或 POCO。[JsonConverter]
(请注意,这与 Newtonsoft 部分不同,其中应用于类型的转换器取代设置中的转换器。)
如果您想在多个属性上使用自定义
JsonConverter
并且想知道 Read/Write 方法在哪个属性上触发,还有另一种解决方案。您需要自定义 JsonConverter
和自定义 JsonConverterAttribute
类。你需要像这样实现它:
public class StringTypeJsonConverter : JsonConverter<string>
{
readonly string _propertyName;
public StringTypeJsonConverter (string propertyName) : base()
{
_propertyName = propertyName;
}
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
//////////////////////////////////////
// do something with your _propertyName
//////////////////////////////////////
return reader.GetString()
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
//////////////////////////////////////
// do something with your _propertyName
//////////////////////////////////////
writer.WriteString(value);
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class StringJsonConverterAttribute: JsonConverterAttribute
{
readonly string _propertyName;
public StringJsonConverterAttribute(string propertyName) : base()
{
_propertyName = propertyName;
}
public override JsonConverter? CreateConverter(Type typeToConvert)
{
return new StringJsonConverterAttribute(_propertyName);
}
}
当你获得这一部分后,你所需要的就是在你的字符串属性上使用这个属性:
class MyMailContent
{
[StringJsonConverter(nameof(Name))]
public string Name { get; set; }
[StringJsonConverter(nameof(Subject))]
public string Subject { get; set; }
[StringJsonConverter(nameof(Body))]
public string Body { get; set; }
}