我的模型包含通过 [ObservableProperty]
工具包
从
CommunityToolkit.Mvvm
字段自动生成的可观察属性,我想使用 System.Text.Json
JsonSerializerContext
序列化它们。但当我这样做时,我的所有财产都消失了。我该如何解决这个问题?
这是我的代码:
using CommunityToolkit.Mvvm.ComponentModel;
using System.IO.Ports;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
namespace WinFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var _result = JsonSerializer.Serialize<EmptyConnection>(new EthernetConnection() { IP="192.168.125.201",Port=9100}, new JsonSerializerOptions()
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),
TypeInfoResolver = EmptyConnectionGenerationContext.Default,
IgnoreReadOnlyProperties = true,
});
}
[JsonDerivedType(typeof(EmptyConnection), typeDiscriminator: "EmptyConnection")]
[JsonDerivedType(typeof(SerialPortConnection), typeDiscriminator: "SerialPortConnection")]
[JsonDerivedType(typeof(EthernetConnection), typeDiscriminator: "EthernetConnection")]
public partial class EmptyConnection : ObservableObject
{
}
public partial class SerialPortConnection : EmptyConnection
{
[ObservableProperty]
string _PortName = "";
[ObservableProperty]
int? _BaudRate = null;
[ObservableProperty]
Parity? _Parity = null;
[ObservableProperty]
int? _DataBits = null;
[ObservableProperty]
StopBits? _StopBits = null;
[ObservableProperty]
string _PortFeature = "";
}
public partial class EthernetConnection : EmptyConnection
{
[ObservableProperty]
string _IP = "";
[ObservableProperty]
int _Port = 0;
}
[JsonSerializable(typeof(EmptyConnection))]
[JsonSerializable(typeof(SerialPortConnection))]
[JsonSerializable(typeof(EthernetConnection))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(int?))]
[JsonSerializable(typeof(Parity?))]
[JsonSerializable(typeof(StopBits?))]
public partial class EmptyConnectionGenerationContext : JsonSerializerContext
{
}
}
}
程序运行后,生成一个空的Json:
{"$type":"EthernetConnection"}
如果我不使用
TypeInfoResolver
中的JsonSerializerOptions
,它将成功生成Json,如下所示:
{"$type":"EthernetConnection","IP":"192.168.125.201","Port":9100}
我的代码有什么问题?
您遇到的是使用源生成器的两种技术之间的交互错误:
JsonSerializerContext
使用源生成器在编译时生成指定类型的序列化器。CommunityToolkit.Mvvm
的[ObservableProperty]
使用源生成器为指定字段生成可观察的属性。您希望这两个源生成器能够协同工作,以便
CommunityToolkit.Mvvm
生成的属性将被 JsonSerializerContext
拾取并序列化,但不幸的是,这似乎没有实现。构建单个项目时,由一次源生成器生成的代码对另一个源生成器不可见。如需确认,请参阅:
那么你有什么选择?
首先,您可以按照docs中显示的模式手动实现可观察属性,删除
[ObservableProperty]
并添加字段所需的属性。例如
[ObservableProperty]
string _IP = "";
会成为
string _IP = "";
public string IP
{
get => _IP;
set => SetProperty(ref _IP, value);
}
其次,正如您已经注意到的,您可以使用基于反射的序列化而不是基于源生成的序列化:
var options = new JsonSerializerOptions()
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),
//TypeInfoResolver = EmptyConnectionGenerationContext.Default, // REMOVE THIS
IgnoreReadOnlyProperties = true,
};
var _result = JsonSerializer.Serialize<EmptyConnection>(new EthernetConnection() { IP="192.168.125.201", Port=9100 }, options);
Console.WriteLine(_result); // {"$type":"EthernetConnection","IP":"192.168.125.201","Port":9100}
最后,按照Steven Blom的这个答案的建议,您可以将数据模型和
JsonSerializerContext
提取到单独的项目中,使序列化上下文项目依赖于数据模型项目。如果这样做,您可以保证 System.Text.Json 的源生成器将看到您的数据模型的可观察属性,因为包含您的数据模型的项目已经构建。然后,您的 WinFormsApp1
代码需要引用这两个项目,以便使用 JsonSerializerContext
序列化您的数据模型。