简体   繁体   中英

JSON Deserializing string value to List<T> using Newtonsoft - constructor arg is null in C#

I am using Newtonsoft libraries for serialization and deserialization json object. The reference code is below:

 public abstract class BaseNode
{
    [JsonConstructor]
    protected BaseNode(string [] specifications)
    {
        if (specifications == null)
        {
            throw new ArgumentNullException();
        }
        if (specifications.Length == 0)
        {
            throw new ArgumentException();
        }

        Name = specifications[0];
        Identifier = specifications[1];
        //Owner = specifications[2];
    }

    public string Name{ get; protected set; }
    public string Identifier { get; protected set; }
    public string Owner { get; protected set; }
}


public class ComputerNode: BaseNode
{
    [JsonConstructor]
    public ComputerNode(string[] specifications):base(specifications)
    {
        Owner = specifications[2];
    }
}

Serialization works fine and I can save the json formatted data in a file. I am storing a list of ComputerNode objects in a file. Following code for file read/write operation:

public class Operation<T>
{
    public string path;

    public Operation()
    {
        var path = Path.Combine(Directory.GetCurrentDirectory(), "nodes.txt");

        if (File.Exists(path) == false)
        {
            using (File.Create(path))
            {
            }
        }
        this.path = path;
    }

    public void Write(string path, List<T> nodes)
    {
        var ser = JsonConvert.SerializeObject(nodes);

        File.WriteAllText(path, ser);
    }

    public List<T> Read(string path)
    {
        var text = File.ReadAllText(path);

        var res =  JsonConvert.DeserializeObject<List<T>>(text);
        return res;
    }

}

The expected file Read result should be a list of ComputerNode objects stored in a file. However, while deserialization - creating an object of ComputerNode, correct constructor is called but the argument (string[] specifications) is null.

Is there any better way to work with it.

Please do not suggest to change BaseNode.cs or ComputerNode.cs

Thanks for suggestion...

Correct Answer

Overridden with new Json constructor. In BaseNode.cs

    [JsonConstructor]
    public BaseNode(string Owner, string Name, string Identifier)
    {
        this.Name = Name;
        this.Identifier = Identifier;
    }

and Overridden a Json constructor - ComputerNode.cs

    [JsonConstructor]
    public ComputerNode(string Owner, string Name, string Identifier):base(Owner, Name, Identifier)
    {
        this.Owner = Owner;
    }

https://stackoverflow.com/a/23017892/34092 states:

It is important that the constructor parameter names match the corresponding property names of the JSON object for this to work correctly.

Your constructor parameter is called specifications . There is no property in the JSON with the name of specifications . This is why the value is passed as null.

See also http://www.newtonsoft.com/json/help/html/JsonConstructorAttribute.htm .

in practice if you run

var ser = JsonConvert.SerializeObject(nodes);
File.WriteAllText(path, ser);

where nodes is a List<T>

then

var text = File.ReadAllText(path);
var res =  JsonConvert.DeserializeObject<List<T>>(text);

where res is a List<T>

According to the JsonConstructor documentation: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConstructorAttribute.htm

Instructs the JsonSerializer to use the specified constructor when deserializing that object.

No where it is said that there will be a constructor parameter related with the string to be deserialized.

in fact the constructor you designate ( [JsonConstructor] ) try to override the result of the deserialization with an always null parameter

In your case you should have

[JsonConstructor]
protected BaseNode()
{

}

to avoid the constructor over interacting with the deserialization.

IMHO, the deserializer will never (according to documentation) give a parameter to a constructor.

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