Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json Deserialize Protected Property [duplicate]

Tags:

c#

json.net

I have a class property set, and fixed in the constructor, example below is a Guid.NewGuid()..

The rationale being to only allow the class to populate, on creation.. so it's set in the constructor, and marked only as get; - works fine, until i serialize / deserialize to Json.

It seems that because there is no set; the deserialization fails.. and the constructor steps in and creates a new guid

I have tried internal, private, and protected set .. but all result in a regeneration of the property, the only way i can get it to work is by marking Id as {get;set;},

class Foo
{
    public Foo() => Id = Guid.NewGuid().ToString();
    public string Id { get; set; }
}

which then means you can simply do:

var obj = new Foo();
obj.Id = "Any Old Rubbish";

Is there a way around this at all?

Short sample:

class Program
{
    static void Main()
    {
        var obj = new Foo();
        Console.WriteLine(obj.Id);

        var serialize = JsonConvert.SerializeObject(obj);
        var deserialize = JsonConvert.DeserializeObject<Foo>(serialize);
        Console.WriteLine(deserialize.Id);

        Console.ReadLine();
    }
}

class Foo
{
    public Foo() => Id = Guid.NewGuid().ToString();

    public string Id { get; }
}

Output:

7868a298-f20d-4719-85ef-ba64c8658819
34fe422c-9555-4d17-ae1a-9fbf21af1b71
like image 958
m1nkeh Avatar asked Feb 28 '18 12:02

m1nkeh


1 Answers

The following image (it is not done by me but is found in this question) shows how the algorithm for JsonConvert.DeserializeObjectworks. As you can see the constructor of the serialized type is called almost always. That's why you have to use a constructor with parameters as the left most path of the image shows.

JsonConvert.DeserializeObject algorithm

The following shows a modification of your example using a constructor with parameters.

class Program
{
  static void Main()
  {
    var obj = new Foo(Guid.NewGuid().ToString());
    Console.WriteLine(obj.Id);

    var serialize = JsonConvert.SerializeObject(obj);
    var deserialize = JsonConvert.DeserializeObject<Foo>(serialize);
    Console.WriteLine(deserialize.Id);

    Console.ReadLine();
  }
}

class Foo
{
  public Foo(String Id) => this.Id = Id;        
  public string Id { get; }
}

This will result in having the same guid before and after serialization while there is no need to use public string Id { get; set;} as you didn't want to.

like image 86
Bee Avatar answered Sep 19 '22 14:09

Bee