当前位置: 首页 > 知识库问答 >
问题:

C# JSON 反序列化 System.NotSupportedException

韶浩皛
2023-03-14

我一直在做一个项目,需要通过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;
    }

JSON转换器

    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();

    }

我该怎么修?提前感谢!:)

编辑:我添加了我试图反序列化的类。如果我没有提供足够的细节或我犯了愚蠢的错误,我很抱歉,我仍然是一名学生,并试图第一次搞砸这些事情的大部分。

共有2个答案

宗政文彬
2023-03-14

该错误准确地说明了错误所在以及如何修复它。

反序列化的目标类(用户和商店)需要:

  • 无参数构造函数(恕我直言,这是最简单,最直接的方法);
  • 单数参数化构造函数;或
  • 不支持使用“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));
    }
}
安建木
2023-03-14

您的异常表示您不能反序列化没有默认(无参数)构造函数的类。

正在反序列化的类,或作为该类属性包含的类之一,具有接受参数的构造函数,并且没有默认构造函数。

反序列化程序无法创建该类的实例,因为它没有传递给该构造函数的参数。

如果没有看到您试图反序列化的类的定义,我无法提供任何进一步的帮助。

编辑:它看起来像Newtonsoft。Json足够好,可以提供一些属性,您几乎正确地使用这些属性来解决这个问题。JsonConstructorAttribute将匹配序列化字符串中的属性,如果名称匹配(忽略大小写),则将使用构造函数参数进行反序列化。

[JsonConstructor]
public Sellable(int value, string name){
    Value = value;
    Name = name;
}

感谢Brian Rogers的回答,为我找到相关文档提供了线索!

 类似资料:
  • 我想解析这个json文件。 {“特征”:[{“类型”:“特征”,“几何”:“{“类型”:“多边形”,“坐标”:[[26.4217861898109,40.127607984644],[26.4219934821323,40.1275230229872],[26.4218810759267,40.1273800013679],[26.4216801413981,40.1274730404221],[

  • 问题内容: 我有以下需要反序列化的Json字符串。 第一个字段“ 123456789”是一个ID号,因此基本上该值可以根据要查询的数据而有所不同。 我在Visual Studio中使用C#。显然,因为第一个字段的值可以更改,所以我无法使用预定义的类将JSON反序列化为该字段,因为该字段将用作类名,但该字段的值与该类名不匹配。 有没有一种方法可以将其反序列化为某种动态类,但仍可以像访问预定义类一样访

  • 问题内容: 我对反序列化json对象几乎没有问题。我的json来自http网址: 我下载的JSON的屏幕 我不知道如何反序列化以动态创建按钮。我想出了如何用文本创建按钮,但是我不知道如何使用它们所具有的选项来创建按钮。我尝试在Windows Form应用程序中获取这些选项进行测试,但应用程序将崩溃。谢谢你的帮助。 问题答案: 您的课程应类似于: 然后,您应该可以使用Newtonsoft.Json反

  • 我对反序列化json对象没有什么问题。我的json来自超文本传输协议url: 我下载的JSON的屏幕 我不知道如何反序列化以动态创建按钮。我知道如何使用文本创建按钮,但我不知道如何使用它们拥有的选项制作它们。我尝试在Windows表单应用程序中获取这些选项进行测试,但应用程序会崩溃。谢谢您的帮助。

  • 我从 REST API 获得以下 JSON 作为响应。 并尝试使用下面的代码进行解析,但这不会导致正确的反序列化类型。 下面是我在JSON响应中收到的字段的类。 缺少了什么?

  • 问题内容: 我需要将Objective- C对象序列化和反序列化为JSON以存储在CouchDB中。人们是否有通用解决方案最佳实践的示例代码?我看了几个JSON框架,它们在NSDictionary / NSArray级别停止了。即,许多框架会将NSDictionary / NSArray序列化和反序列化为JSON。但是我仍然要做将NSDictionary转换为Objective-C对象的工作。 为