如何在反序列化JSON文件时解决InvalidOperationException?

编程语言 2026-07-08

我在用.NET MAUI开发一个迷你银行应用,打算在点击「登录」或「注册」按钮时从JSON文件加载客户数据。

下面是我的 Customer 类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.Json.Serialization;

namespace ReadOnlyBankingSystem.Models
{
    public class Customer
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }    
        public string Email { get; set; }
        public string Address { get; set; }
        public DateOnly DateOfBirth { get; set; }

        public ObservableCollection<BankAccount> Accounts { get; set; }

        public Customer(string username, string password, string firstName, string lastName, string email, string address, DateOnly dateOfBirth)
        {
            this.Username = username;
            this.Password = password;
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Email = email;
            this.Address = address;
            this.DateOfBirth = dateOfBirth;
            this.Accounts = new ObservableCollection<BankAccount>();
        }
    }

    [JsonSerializable(typeof(Dictionary<string, Customer>))]
    internal sealed partial class CustomerContext : JsonSerializerContext
    {
    }
}

Deserializing works fine when the Customer has no open accounts, which are stored in the ObservableCollection. But once when a BankAccount is created and added to the JSON file, my program throws an InvalidOperationException when it tries to deserialize the contents of the file.

以下是相关错误信息:

System.InvalidOperationException
  HResult=0x80131509
  Message=Each parameter in the deserialization constructor on type 'ReadOnlyBankingSystem.Models.BankAccount' must bind to an object property or field on deserialization. Each parameter name and type must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The name match can be case-insensitive.
  Source=System.Text.Json

这是我的BankAccount类:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.Json.Serialization;

namespace ReadOnlyBankingSystem.Models
{
    public class BankAccount
    {
        [JsonInclude]
        public readonly Guid AccountId;
        [JsonInclude]
        public readonly DateTime DateCreated;
        [JsonInclude]
        public readonly int PIN;
        public decimal Amount { get; set; }
        public ObservableCollection<Transaction> Transactions { get; set; }

        public BankAccount(Guid accountId, DateTime dateCreated, int pin, decimal initialAmount)
        {
            AccountId = accountId;
            DateCreated = dateCreated;
            Amount = initialAmount;
            PIN = pin;
            Transactions = new ObservableCollection<Transaction>();
        }
    }
}

以及用于序列化和反序列化数据的函数如下:

public async Task<Dictionary<string, Customer>> ReadFromJsonFile(string filename)
{
    string appDataFilePath = GetAppDataFilePath(filename);
    using var stream = File.OpenRead(appDataFilePath);
    using var reader = new StreamReader(stream);
    var contents = await reader.ReadToEndAsync();
    var customerDictionary = JsonSerializer.Deserialize(contents, CustomerContext.Default.DictionaryStringCustomer);

    return customerDictionary;
}

public async Task WriteToJsonFile(string filename, Dictionary<string, Customer> customerData) 
{
    string appDataFilePath = GetAppDataFilePath(filename);
    using var stream = File.OpenWrite(appDataFilePath);
    using var writer = new StreamWriter(stream);
    var options = new JsonSerializerOptions { WriteIndented = true };
    var contents = JsonSerializer.Serialize(customerData, options);
    await writer.WriteAsync(contents);
}

解决方案

问题在于 System.Text.Json 无法推断 Amount 应绑定到 initialAmount 构造函数的参数。将构造函数参数的名称改为 amount 就能解决我的问题。

不过我建议不要用这种方式来设计用于序列化的类。通常最好为序列化创建专门的类型,即数据传输对象(DTO)。这可以更好地管理诸如向后兼容性之类的事项,以及传输/存储与应用逻辑之间的分离。记录类型在这方面通常很有用,因此我会创建一个类似这样的类型:

public record BankAccountDTO(
    Guid AccountId, 
    DateTime DateCreated, 
    int Pin, 
    decimal Amount, 
    Transaction[] Transactions)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章