如何在反序列化JSON文件时解决InvalidOperationException?
我在用.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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。