0

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;
    }
jack_t
  • 145
  • 3
  • 9
  • What's your JSON look like? I dont see why you'd need these passed into the constructor when deserializing a well structure JSON object. It should just populate the properties as you'd expect. – Skintkingle Jul 07 '17 at 14:07
  • [ { "Name": "jack", "Identifier": "123345", "Owner": "CiiW" }, { "Name": "didi", "Identifier": "1dd123345", "Owner": "C12W" } ] – jack_t Jul 07 '17 at 14:17
  • sorry it did not add indentation in SO editor. – jack_t Jul 07 '17 at 14:17
  • Please edit your question to include the JSON. Is your issue just that the constructor is passed a null parameter? What happens if you tag a parameterless constructor. the deserializer should populate the properties for you, you dont need a funky constructor to assign everything. – Skintkingle Jul 07 '17 at 14:19

2 Answers2

1

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 .

mjwills
  • 23,389
  • 6
  • 40
  • 63
0

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.

tschmit007
  • 7,559
  • 2
  • 35
  • 43