我有一个巨大的json文件,所以我使用下面的代码,实际上它的工作。
using (FileStream? fileStream = new FileStream("hugefile.json", FileMode.Open))
{
IAsyncEnumerable<Person?> people = JsonSerializer.DeserializeAsyncEnumerable<Person?>(fileStream);
await foreach (Person? person in people)
{
Console.WriteLine($"Hello, my name is {person.Name}!");
}
}
我的问题在于Person类,它是用protobuf生成的。它包含一个名为TrackingDatas的属性,它具有ProtoMember属性,您可以在下面看到。但是在我的json中,属性名称是TrackingData。我想反序列化它,但没有任何添加或删除ProtoBuf类。有人知道吗?
[global::ProtoBuf.ProtoMember(2, Name = @"TrackingData")]
public global::System.Collections.Generic.List<EntityTrackingActivity> TrackingDatas { get; } = new global::System.Collections.Generic.List<EntityTrackingActivity>();
我试过下面的代码来更改属性的名称,但它不适合我。
public class CustomNamingPolicy : JsonNamingPolicy
{
private readonly Dictionary<string, string> NameMapping = new Dictionary<string, string>()
{
[nameof(OASISLevel2TrackingPacket.EntityTracking.TrackingDatas)] = "TrackingData"
};
public override string ConvertName(string name)
{
var a = NameMapping.GetValueOrDefault(name, name);
return a;
}
}
var options = new JsonSerializerOptions()
{
PropertyNamingPolicy = new CustomNamingPolicy()
};
using (FileStream? fileStream = new FileStream("hugefile.json", FileMode.Open))
{
IAsyncEnumerable<Person?> people = JsonSerializer.DeserializeAsyncEnumerable<Person?>(fileStream, options);
await foreach (Person? person in people)
{
Console.WriteLine($"Hello, my name is {person.Name}!");
}
}
1条答案
按热度按时间jutyujz01#
这里有两个问题:
1.属性
TrackingDatas
的名称与JSON名称"TrackingData"
不匹配,但您的类型是由Protobuf自动生成的,因此您不能轻易修改它。通过添加一个
PropertyNamingPolicy
,将所有名为TrackingDatas
(所有类型)的属性重新Map到"TrackingData"
,您已经正确地修复了这个问题。1.您的收藏财产
为只读,但System.Text.Json不支持反序列化只读集合属性。
如需确认,请参见 Can System.Text.Json.JsonSerializer serialize collections on a read-only property?。
那么,解决第二个问题的方法是什么?
首先,您可以反序列化到一些合适的
PersonDTO
,然后使用AutoMapper将DTOMap到Person
。其次在.NET 5及更高版本中,如果自动生成的
Person
类声明为partial
,例如:你可以添加一个参数化的构造函数,它带有一个
List<EntityTrackingActivity> trackingDatas
参数,然后用[JsonConstructor]
标记它,如下所示:现在您将能够反序列化
TrackingDatas
属性。演示小提琴#1 here。
第三,在.NET 7及更高版本中,Microsoft增加了以编程方式自定义System.Text.Json为每个.NET类型创建的serialization contract的功能。使用此API,您可以添加一个typeInfo modifier,将所有JSON属性名Map到
ProtoMemberAttribute.Name
的值,并将合成setter添加到仅获取List<T>
属性。这种方法完全避免了以任何方式修改类型的需要。首先,添加以下扩展方法:
然后反序列化,例如如下:
注意事项:
await using
语法来处置文件流。FileStream
访问,将useAsync : true
传递给FileStream
构造函数。有关可能的性能影响的讨论,请参阅文档。CustomNamingPolicy
不再需要这种方法。演示小提琴#2 here。