简体   繁体   中英

json.net Unable to Deserialize to Object List

I am trying to create a JSON file that contains a list of parts for computers.

My Parts Class

namespace Part_Class
{
    public class Part_DB : IEnumerable<Part>
    {
        public List<Part> Parts = new List<Part>();

        public IEnumerator<Part> GetEnumerator()
        {
            return this.Parts.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public class Model
    {
        public String Name { get; set; } // E6430, M4600, T4220

        public Model(string Name)
        {
            this.Name = Name;
        }
    }

    public class Category
    {
        public String Name { get; set; } // E6430, M4600, T4220

        public Category(string Name)
        {
            this.Name = Name;
        }
    }

    public class Part
    {
        public List<Model> Models = new List<Model>(); //E6420
        public string PartNumber { get; set; } //PPHPX, UK717
        public string Description { get; set; } // "320GB Hard Drive", "E6410 keyboard"
        public List<Category> Categories = new List<Category>(); //Hard Drive, Keyboard 
        public bool HeroKit { get; set; } //Y or N
    }
}

First I create a handful of Model, Categories, and Parts.

....
Model E6410 = new Model("E6410");
Model M4600 = new Model("M4600");
Model M4700 = new Model("M4700");

Category Keyboard = new Category("Keyboard");
Category Hard_Drive = new Category("Hard Drive");

Part PPHPX = new Part();
PPHPX.PartNumber = "PPHPX";
PPHPX.Models.Add(M4600);
PPHPX.Models.Add(M4700);
PPHPX.Description = "320GB Spindle Hard Drive";
PPHPX.Categories.Add(Hard_Drive);
PPHPX.HeroKit = true;

Part UK717 = new Part();
UK717.PartNumber = "UK717";
UK717.Models.Add(E6410);
UK717.Description = "102 Key Non Backlit";
UK717.Categories.Add(Keyboard);
UK717.HeroKit = true;

//I store those parts into a Part_DB Object
Part_DB Stored = new Part_DB();
Stored.Parts.Add(PPHPX);
Stored.Parts.Add(UK717);

//Then take that object and serialize it into a string
string jsonStr = JsonConvert.SerializeObject(Stored, Formatting.Indented);  

//Then save it to a file
System.IO.File.WriteAllText(@"C:\****\Parts.json", jsonStr);
....

This outputs the following json file.

[
  {
    "Models": [
      {
        "Name": "M4600"
      },
      {
        "Name": "M4700"
      }
    ],
    "Categories": [
      {
        "Name": "Hard Drive"
      }
    ],
    "PartNumber": "PPHPX",
    "Description": "320GB Spindle Hard Drive",
    "HeroKit": true
  },
  {
    "Models": [
      {
        "Name": "E6410"
      }
    ],
    "Categories": [
      {
        "Name": "Keyboard"
      }
    ],
    "PartNumber": "UK717",
    "Description": "102 Key Non Backlit",
    "HeroKit": true
  }
]

I am having trouble doing the reverse. Deserialize the JSON file back into a Part_DB Object. Here is my attempt

List<string> errors = new List<string>();

try
{
    //Create a string of the JSON File
    string jsonStr;
    using (StreamReader file = File.OpenText(@"C:\****\Parts.json"))
    {
        jsonStr = file.ReadToEnd();
    }

    // Deserilize object into the Part_DB
    Part_DB Stored = JsonConvert.DeserializeObject<Part_DB>(jsonStr,
        new JsonSerializerSettings
        {
            Error = delegate(object senders, Newtonsoft.Json.Serialization.ErrorEventArgs args)
            {
                errors.Add(args.ErrorContext.Error.Message);
                //Debug.WriteLine(args.ErrorContext.Error.Message);
                args.ErrorContext.Handled = true;
            },
        });
}
catch (Exception ex) {
    Console.WriteLine(ex);
}

I suspect it has something to do with the somewhat oddness of your top-level model actually inheriting from IEnumerable<T> . I was able to successfully deserialize the file produced into a Part_DB by using the following:

var newObj = JsonConvert.DeserializeObject<List<Part>>( json );
var partDb = new Part_DB();
partDb.Parts.AddRange( newObj );

The json variable contains the contents of the file, which is actually an array of Part objects, not a complete Part_DB object. Then to reconstruct the entire Part_DB you need to take the deserialized array and add it back into the Parts collection of the Part_DB .

If you want to deserialize straight into a Part_DB you're going to have to change your model so that Part_DB isn't inherited from IEnumerable<T> .

public class Part_DB
{
    public List<Part> Parts = new List<Part>();
}

Then you can just deserialize directly into that type.

JsonConvert.DeserializeObject<Part_DB>( json );

But it will change your JSON a bit.

{
  "Parts": [
    {
      "Models": [
        { "Name": "M4600" },
        { "Name": "M4700" }
      ],
      "Categories": [
        { "Name": "Hard Drive" }
      ],
      "PartNumber": "PPHPX",
      "Description": "320GB Spindle Hard Drive",
      "HeroKit": true
    },
    {
      "Models": [
        { "Name": "E6410" }
      ],
      "Categories": [
        { "Name": "Keyboard" }
      ],
      "PartNumber": "UK717",
      "Description": "102 Key Non Backlit",
      "HeroKit": true
    }
  ]
}

I think that for the Json.NET the Part_DB is just an object (which happens to be enumerable, but that's not important) so it is looking for the JSON that looks more like:

{ "Parts": and here should be your output from serialization}

The output you got from serialization is actually just the serialized List<Part> so try deserializing to it first, create a new Part_DB object and then assign that list to the Parts property.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM