我一直在研究一个需要通过JSON文件保存和加载数据的项目。这个JSON文件包含其他对象的各种列表。但是,当我继续对文件进行反序列化时,会发生以下情况:
系统。NotSupportedException:不支持没有无参数构造函数、单一参数化构造函数或带有'JsonConstructorAttribute'注释的参数化构造函数的类型反序列化。
处理反序列化的代码如下:
public void LoadFromJson() {
int userCount = File.ReadAllLines(folder + "/users").Length;
int shopCount = File.ReadAllLines(folder + "/shops").Length;
using (FileStream fileUsers = File.Open(folder + "/users", FileMode.Open, FileAccess.Read)) {
StreamReader srUser = new StreamReader(fileUsers);
for(int i=0; i<userCount; i++){
ListOfUsers.Add(JsonSerializer.Deserialize<User>(srUser.ReadLine()));
}
srUser.Close();
fileUsers.Close();
}
using (FileStream fileShops = File.Open(folder + "/shops", FileMode.Open, FileAccess.Read)){
StreamReader srShops = new StreamReader(fileShops);
for(int i=0; i<shopCount; i++){
ListOfShops.Add(JsonSerializer.Deserialize<Shop>(srShops.ReadLine()));
}
srShops.Close();
fileShops.Close();
}
}
类我试图反序列化
public abstract class Shop{
public List<Sellable> ShopList { get; set; }
public int TotalValue { get; set; }
public string shopName { get; set; }
public Shop(List<Sellable> list, string shopname){
ShopList = list;
shopName = shopname;
}
public abstract bool AddToShop(Sellable item);
public abstract bool RemoveFromShop(string item);
public abstract int GetValue(string name);
public abstract string PrintShop();
}
public abstract class Furniture : Sellable{
public int Space { get; set; }
public Conditions Condition { get; set; }
public Materials Material { get; set; }
[JsonConstructorAttribute]
public Furniture(int val, int spc, string nm, Conditions condition, Materials material) : base (val, nm){
Space = spc;
Condition = condition;
Material = material;
}
}
public abstract class Sellable{
public int Value { get; set; }
public string Name { get; set; }
[JsonConstructorAttribute]
public Sellable(int val, string name){
Value = val;
Name = name;
}
JsonConverter
public class SellableConverter : JsonConverter<Sellable>{
public enum Type{
Sellable,
Furniture,
Wearable,
}
public override Sellable Read(ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject) throw new JsonException();
if (!reader.Read()
|| reader.TokenType != JsonTokenType.PropertyName
|| reader.GetString() != "Type") throw new JsonException();
if (!reader.Read() || reader.TokenType != JsonTokenType.Number) throw new JsonException();
Sellable baseClass;
Type typeDiscriminator = (Type)reader.GetInt32();
switch (typeDiscriminator)
{
case Type.Furniture:
if (!reader.Read() || reader.GetString() != "TypeValue") throw new JsonException();
if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject) throw new JsonException();
baseClass = (Furniture.Furniture)JsonSerializer.Deserialize(ref reader, typeof(Furniture.Furniture), options);
break;
case Type.Wearable:
if (!reader.Read() || reader.GetString() != "TypeValue") throw new JsonException();
if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject) throw new JsonException();
baseClass = (Wearable)JsonSerializer.Deserialize(ref reader, typeof(Wearable), options);
break;
case Type.Sellable:
if (!reader.Read() || reader.GetString() != "TypeValue") throw new JsonException();
if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject) throw new JsonException();
baseClass = (Sellable)JsonSerializer.Deserialize(ref reader, typeof(Sellable));
break;
default:
throw new NotSupportedException();
}
if (!reader.Read() || reader.TokenType != JsonTokenType.EndObject) throw new JsonException();
return baseClass;
}
public override void Write(Utf8JsonWriter writer, Sellable value, JsonSerializerOptions options)
{
writer.WriteStartObject();
if (value is Furniture.Furniture derivedA)
{
writer.WriteNumber("TypeDiscriminator", (int)Type.Furniture);
writer.WritePropertyName("TypeValue");
JsonSerializer.Serialize(writer, derivedA, options);
}
else if (value is Wearable derivedB)
{
writer.WriteNumber("TypeDiscriminator", (int)Type.Wearable);
writer.WritePropertyName("TypeValue");
JsonSerializer.Serialize(writer, derivedB, options);
}
else if (value is Sellable baseClass)
{
writer.WriteNumber("TypeDiscriminator", (int)Type.Sellable);
writer.WritePropertyName("TypeValue");
JsonSerializer.Serialize(writer, baseClass);
}
else throw new NotSupportedException();
writer.WriteEndObject();
}
}
SaveToJson方法:
public void SaveToJson(){
FileStream fileUsers;
FileStream fileShops;
if(!(File.Exists(folder + "/users"))) fileUsers = File.Create(folder + "/users");
else fileUsers = File.OpenWrite(folder + "/users");
if(!(File.Exists(folder + "/shops"))) fileShops = File.Create(folder + "/shops");
else fileShops = File.OpenWrite(folder + "/shops");
StreamWriter srUser = new StreamWriter(fileUsers);
StreamWriter srShop = new StreamWriter(fileShops);
var serializeOptions = new JsonSerializerOptions();
serializeOptions.Converters.Add(new SellableConverter());
for(int i=0; i<ListOfUsers.Count; i++){
srUser.WriteLine(JsonSerializer.Serialize<User>(ListOfUsers[i]), serializeOptions);
Console.WriteLine("Debug: " + "n" + "Object: " + ListOfUsers[i] + "n" + "Json: " + JsonSerializer.Serialize<User>(ListOfUsers[i]));
}
for(int i=0; i<ListOfShops.Count; i++){
srShop.WriteLine(JsonSerializer.Serialize<Shop>(ListOfShops[i]), serializeOptions);
Console.WriteLine("Debug: " + "n" + "Object: " + ListOfShops[i] + "n" + "Json: " + JsonSerializer.Serialize<Shop>(ListOfShops[i]));
}
srUser.Close();
fileUsers.Close();
srShop.Close();
fileShops.Close();
}
我该如何修复它?提前感谢!:)
编辑:我添加了我试图反序列化的类。如果我没有给出足够的细节或者我犯了愚蠢的错误,我很抱歉,我还是一个学生,第一次尝试弄乱这些东西
你的异常说明你不能反序列化没有默认(无参数)构造函数的类。
要反序列化的类,或作为该类属性包含的类之一,具有接受参数的构造函数,并且没有默认构造函数。
反序列化器不能创建该类的实例,因为它没有参数可以传递给该构造函数。
如果没有看到您试图反序列化的类的定义,我无法进一步提供帮助。
编辑:它看起来像Newtonsoft。Json很好地提供了一些属性,您几乎可以正确使用这些属性来解决这个问题。如果名称匹配(忽略大小写),JsonConstructorAttribute
将与构造函数参数匹配被反序列化的序列化字符串的属性。
[JsonConstructor]
public Sellable(int value, string name){
Value = value;
Name = name;
}
感谢Brian Rogers的回答,为我找到相关文档提供了线索!
错误说明了错误所在以及如何修复。
反序列化的目标类(User和Shop)需要:
- 一个无参数的构造函数(IMHO最简单,最直接的方式);
- 是一个奇异参数化构造函数;或
- 不支持带有'JsonConstructorAttribute'注释的参数化构造函数。
或者你可以反序列化到一个动态或对象,并映射属性(参见反序列化JSON到c#动态对象?对于小样本)
还有,这真的让我很烦,为什么你读文件,然后读每一行?你应该这样做
using(var fileUsers = File.Open(folder + "/users", FileMode.Open, FileAccess.Read))
using(var srUser = new StreamReader(fileUsers))
{
string line;
while((line = srUser.ReadLine()) != null)
{
ListOfUsers.Add(JsonSerializer.Deserialize<User>(line));
}
}
我得到了一个类似的运行时错误使用Blazor WASM
(Blazor WebAssembly)和System.Text.Json
:
失败:MyProject.Client.Shared.Error [0]错误:ProcessError -类型:系统。NotSupportedException消息:没有无参数构造函数的类型反序列化单一参数化构造函数,或参数化构造函数不支持带有'JsonConstructorAttribute'的注释。类型"MyProject.Shared.Models.DTO.MyDto"。路径:[0]美元。myDtos [0] |LineNumber: 0 | BytePositionInLine: 406。例外:系统。NotSupportedException:不带无参数构造函数、单个参数化构造函数或用'JsonConstructorAttribute'注释的参数化构造函数是不受支持的。"MyProject.Shared.Models.DTO.MyDto"类型。路径:[0]美元。myDtos[0] | LineNumber: 0 | BytePositionInLine: 406。——比;系统。NotSupportedException:没有无参数构造函数的类型反序列化,单一参数化构造函数,或用不支持'JsonConstructorAttribute'。类型"MyProject.Shared.Models.DTO.MyDto"。
使用你的模型在我的世界里最简单的修复是简单地添加一个无参数的构造函数:
public Sellable(){
}
如果您需要默认值,请使用构造函数链接,这也适用:
public Sellable() : this(0, "")
{
}
https://stackoverflow.com/a/1814965/3850405