使用 System.Text.Json 序列化和反序列化 IReadOnlyCollection<T>
Serializing and deserializing IReadOnlyCollection<T> using System.Text.Json
我有一个 (C#) 对象,我想使用 .NET 6 System.Text.Json 序列化程序对其进行序列化。我的对象看起来像这样:
private List<Substitution> _substitutions;
public string? Name { get; private set; }
public string EmailAddress { get; private set; }
public IReadOnlyCollection<Substitution> Substitutions => _substitutions.AsReadOnly();
当我实例化并序列化它时,我得到一个看起来像预期的 JSON 字符串:
{
"Name":"Foo Bar",
"EmailAddress":"my-email@domain.com",
"Substitutions":[
{"Key":"Firstname","Value":"Foo"},
{"Key":"Lastname","Value":"Bar"}
]
}
现在当我尝试将这个值反序列化回一个对象时,我得到了这个奇怪的错误:
Each parameter in the deserialization constructor on type 'objectname' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive.'
我几乎已经发现 IReadOnlyCollection 是这里的问题所在。它列在 JSON 序列化/反序列化支持的数据类型中,所以我希望它能工作。该错误说明构造函数缺少接受所有序列化的字段。我玩了一下外壳,所以 JSON 中的字段与属性的名称相匹配,不幸的是没有成功。
该对象包含此构造函数:
public Recipient(string name, string emailAddress, List<Substitution> substitutions)
{
EmailAddress = emailAddress;
Name = name;
_substitutions = substitutions;
}
我以为我在那里很好,但显然不是 ;) 我的想法是我想在对象中维护替换列表,因此公开只读副本是强制性行为。
我的问题是,如何正确反序列化这个对象?
非常感谢!
这是问题的答案,但功劳全部归功于 Paul Karam,因为他在评论中提出了解决方案。
我更改了 Recipient
对象的构造函数,所以它看起来像这样:
public Recipient(string name, string emailAddress, IReadOnlyCollection<Substitution>? substitutions)
{
EmailAddress = emailAddress;
Name = name;
_substitutions = substitutions != null ? substitutions.ToList() : new List<Substitution>();
}
这有效,但是...我的对象有多个构造函数,现在序列化程序不知道要使用哪个构造函数并且结果不一致。要解决这个问题,您可以使用 JsonConstructor
属性提示正确的构造函数。我的对象现在看起来像这样并且工作起来很有魅力:
public Recipient(string emailAddress)
{
_substitutions = new List<Substitution>();
SetEmailAddress(emailAddress);
}
[JsonConstructor]
public Recipient(string name, string emailAddress, IReadOnlyCollection<Substitution>? substitutions)
{
EmailAddress = emailAddress;
Name = name;
_substitutions = substitutions != null ? substitutions.ToList() : new List<Substitution>();
}
这实际上取决于您的业务需求,但您可以完全删除 _substitutions
并像这样声明 Recipient
:
public class Recipient
{
public Recipient(string name, string emailAddress, IReadOnlyCollection<Substitution> substitutions)
{
EmailAddress = emailAddress;
Name = name;
Substitutions = substitutions;
}
public string? Name { get; private set; }
public string EmailAddress { get; private set; }
public IReadOnlyCollection<Substitution> Substitutions { get; private set; }
}
Substitutions
上的私有 setter 使 System.Text.Json
有机会实际设置此 属性。
不需要特殊的构造函数,可以这样反序列化
public class Recipient
{
private List<Substitution>? _substitutions;
private string? _name;
private string? _emailAddress;
public string? Name
{
get { return _name; }
set { if (_name == null) _name = value; }
}
public string? EmailAddress
{
get { return _emailAddress; }
set { if (_emailAddress == null) _emailAddress = value; }
}
public IReadOnlyCollection<Substitution> Substitutions
{
get { return _substitutions.AsReadOnly(); }
set { if(_substitutions==null) _substitutions = value.ToList(); }
}
}
我有一个 (C#) 对象,我想使用 .NET 6 System.Text.Json 序列化程序对其进行序列化。我的对象看起来像这样:
private List<Substitution> _substitutions;
public string? Name { get; private set; }
public string EmailAddress { get; private set; }
public IReadOnlyCollection<Substitution> Substitutions => _substitutions.AsReadOnly();
当我实例化并序列化它时,我得到一个看起来像预期的 JSON 字符串:
{
"Name":"Foo Bar",
"EmailAddress":"my-email@domain.com",
"Substitutions":[
{"Key":"Firstname","Value":"Foo"},
{"Key":"Lastname","Value":"Bar"}
]
}
现在当我尝试将这个值反序列化回一个对象时,我得到了这个奇怪的错误:
Each parameter in the deserialization constructor on type 'objectname' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive.'
我几乎已经发现 IReadOnlyCollection 是这里的问题所在。它列在 JSON 序列化/反序列化支持的数据类型中,所以我希望它能工作。该错误说明构造函数缺少接受所有序列化的字段。我玩了一下外壳,所以 JSON 中的字段与属性的名称相匹配,不幸的是没有成功。
该对象包含此构造函数:
public Recipient(string name, string emailAddress, List<Substitution> substitutions)
{
EmailAddress = emailAddress;
Name = name;
_substitutions = substitutions;
}
我以为我在那里很好,但显然不是 ;) 我的想法是我想在对象中维护替换列表,因此公开只读副本是强制性行为。
我的问题是,如何正确反序列化这个对象? 非常感谢!
这是问题的答案,但功劳全部归功于 Paul Karam,因为他在评论中提出了解决方案。
我更改了 Recipient
对象的构造函数,所以它看起来像这样:
public Recipient(string name, string emailAddress, IReadOnlyCollection<Substitution>? substitutions)
{
EmailAddress = emailAddress;
Name = name;
_substitutions = substitutions != null ? substitutions.ToList() : new List<Substitution>();
}
这有效,但是...我的对象有多个构造函数,现在序列化程序不知道要使用哪个构造函数并且结果不一致。要解决这个问题,您可以使用 JsonConstructor
属性提示正确的构造函数。我的对象现在看起来像这样并且工作起来很有魅力:
public Recipient(string emailAddress)
{
_substitutions = new List<Substitution>();
SetEmailAddress(emailAddress);
}
[JsonConstructor]
public Recipient(string name, string emailAddress, IReadOnlyCollection<Substitution>? substitutions)
{
EmailAddress = emailAddress;
Name = name;
_substitutions = substitutions != null ? substitutions.ToList() : new List<Substitution>();
}
这实际上取决于您的业务需求,但您可以完全删除 _substitutions
并像这样声明 Recipient
:
public class Recipient
{
public Recipient(string name, string emailAddress, IReadOnlyCollection<Substitution> substitutions)
{
EmailAddress = emailAddress;
Name = name;
Substitutions = substitutions;
}
public string? Name { get; private set; }
public string EmailAddress { get; private set; }
public IReadOnlyCollection<Substitution> Substitutions { get; private set; }
}
Substitutions
上的私有 setter 使 System.Text.Json
有机会实际设置此 属性。
不需要特殊的构造函数,可以这样反序列化
public class Recipient
{
private List<Substitution>? _substitutions;
private string? _name;
private string? _emailAddress;
public string? Name
{
get { return _name; }
set { if (_name == null) _name = value; }
}
public string? EmailAddress
{
get { return _emailAddress; }
set { if (_emailAddress == null) _emailAddress = value; }
}
public IReadOnlyCollection<Substitution> Substitutions
{
get { return _substitutions.AsReadOnly(); }
set { if(_substitutions==null) _substitutions = value.ToList(); }
}
}