通过阅读有关.NET 8序列化的公告和文档,我的印象是我们可以序列化到私有字段中.

我试着做以下几件事:

public class User
{
    [JsonInclude]
    [JsonPropertyName("name")]
    private string _name = null!;
    
    public int Age { get; }
            
    [JsonConstructor]
    private User(string name, int age)
    {
        _name = name;
        Age = age;
    }
    
    private User(){}

}

...
var userStr = @"{""name"": ""juan"", ""age"": 31}";
var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    IncludeFields = true,
    IgnoreReadOnlyFields = false
};
var user = JsonSerializer.Deserialize<User>(userStr, options)!;

这就抛出了

Unhandled exception. System.InvalidOperationException: Each parameter in the deserialization constructor on type 'User' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The match can be case-insensitive.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(Type parentType)...

将私有字段更改为公开如下获取方法的属性 public string Name { get; }可以,但问题是我希望它是一个私有领域.在我的实际场景中,我有一个private List<T>,但我只公开了一个public IReadOnlyCollection<T>,它的getter将列表返回为只读.

有没有办法告诉序列化使用私有字段?

推荐答案

问题不在于属性/字段,而在于构造函数参数名称,它们应该与相应的属性/字段名称相匹配.将ctor更改为:

[JsonConstructor]
private User(string _name, int age)
{
    this._name = _name;
    Age = age;
}

Use immutable types and properties: Parameterized constructors个文件:

参数化构造函数的参数名称必须与属性名称和类型匹配.匹配不区分大小写,and the constructor parameter must match the actual property name even if you use 100 to rename a property.

注意,加上JsonIncludeAttribute就足够了.如果你可以让你的Age属性为init-only,那么你可以完全跳过构造函数:

public class User1
{
    [JsonInclude]
    [JsonPropertyName("name")]
    private string _name = null!;
    
    public int Age { get; init; }

    public override string ToString() => $"{_name}: {Age}";
}

var userStr = @"{""name"": ""juan"", ""age"": 31}";
var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
};
var user = JsonSerializer.Deserialize<User1>(userStr, options)!;

Console.WriteLine(user); // prints "juan: 31"

Csharp相关问答推荐

并行令牌更新

为什么Blazor值在更改后没有立即呈现?

使用命令初始化可绑定属性

更新产品但丢失产品ASP.NET Core的形象

如何解决提交按钮后 Select 选项错误空参照异常

为基本审计设置Audit.EntityFramework.Core

异步任务导致内存泄漏

记录类型';==运算符是否与实现IEquatable<;T&>;的类中的';equals&>方法执行等价比较?

在C#中,是否有与变量DISARD对应的C++类似功能?

在PostgreSQL上使用ExecuteSqlRawAsync的C#11原始字符串文字有区分大小写的问题

Blazor Server.NET 8中的Blazore.FluentValidation问题

MSI无法将快捷方式添加到启动文件夹

为什么我的用户界面对象移动到略低于实际目标?

基于C#方法的EF核心过滤查询(缓冲与流)

如何使用IHostedService添加数据种子方法

Xamarin中出错.表单:应用程序的分部声明不能指定不同的基类

获取应用程序版本信息时出现奇怪信息

如何使ExecuteAsync异步运行

与Visual Studio 2022中的.NET框架相比,如何在.NET Core 6中获取错误输出的窗口句柄

无法通过服务控制台启动.NET Core 6.0服务(错误1053)