Deserialize json into C# object for class which has default private constructor

前端 未结 4 1632
误落风尘
误落风尘 2020-12-14 19:03

I need to deserialize json for following class.

public class Test
{
    public string Property { get; set; }

    private Test()
    {
        //NOTHING TO I         


        
相关标签:
4条回答
  • 2020-12-14 19:22

    This is unfortunately not an option for new System.Text.Json.JsonSerializer (core version of Newtonsoft.Json) according to this and this.

    System.Text.Json supports only parameterless constructor

    0 讨论(0)
  • 2020-12-14 19:29

    No need to create a Serializer setting and give assign ConstructorHandling here. Please remember to define the [JsonConstructor] attribute to the private constructor. I have similar case with abstract BaseNode.cs and its concrete ComputerNode.cs implementation. You can create the classes, copy/paste the code below and do some experiment.

        public abstract class BaseNode
    {
        [JsonConstructor] // ctor used when Json Deserializing
        protected BaseNode(string Owner, string Name, string Identifier)
        {
            this.Name = Name;
            this.Identifier = Identifier;
        }
    
        // ctor called by concrete class.
        protected BaseNode(string [] specifications)
        {
            if (specifications == null)
            {
                throw new ArgumentNullException();
            }
            if (specifications.Length == 0)
            {
                throw new ArgumentException();
            }
    
            Name = specifications[0];
            Identifier = specifications[1];
    
        }
    
        public string Name{ get; protected set; }
        public string Identifier { get; protected set; }
    
    }
    
    
    public class ComputerNode: BaseNode
    {
        public string Owner { get; private set; }
    
        [JsonConstructor] // not visible while creating object from outside and only used during Json Deserialization.
        private ComputerNode(string Owner, string Name, string Identifier):base(Owner, Name, Identifier)
        {
            this.Owner = Owner;
        }
    
        public ComputerNode(string[] specifications):base(specifications)
        {
            Owner = specifications[2];
        }
    }
    

    For JSon Read and Write following code helps -

        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, Formatting.Indented);
    
            File.WriteAllText(path, ser);
        }
    
        public List<T> Read(string path)
        {
            var text = File.ReadAllText(path);
    
            var res =  JsonConvert.DeserializeObject<List<T>>(text);
            return res;
        }
    
    }
    

    All the best!

    0 讨论(0)
  • 2020-12-14 19:36

    You can make Json.Net call the private constructor by marking it with a [JsonConstructor] attribute:

    [JsonConstructor]
    private Test()
    {
        //NOTHING TO INITIALIZE
    }
    

    Note that the serializer will still use the public setters to populate the object after calling the constructor.

    EDIT

    Another possible option is to use the ConstructorHandling setting:

    JsonSerializerSettings settings = new JsonSerializerSettings
    {
        ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
    };
    
    Test t = JsonConvert.DeserializeObject<Test>(json, settings);
    
    0 讨论(0)
  • 2020-12-14 19:38

    It doesn't seem like you need to take any extra steps.

    Using Json.NET v6.0.8, the following C# program works inside LINQPad:

    void Main()
    {   
        var o = JsonConvert.DeserializeObject<Test>("{\"Property\":\"Instance\"}");
    
        Debug.Assert(o.Property == "Instance",
            "Property value not set when deserializing.");
    }
    
    public class Test
    {
        public string Property { get; set; }
    
        private Test()
        {
        }
    
        public Test(string propertyValue)
        {
            Property = propertyValue;
        }
    }
    
    0 讨论(0)
提交回复
热议问题