I use Newtonsoft JSON to serialize/deserialize my objects. One of those contains an array with a protected setter because the constructor build the array itself and only the members are manipulated.
This can be serialized without problem but when it comes to deserialization the property it is ignored because it is not public. I tried a custom converter with it is also not called because it is not public.
This is a minimized example:
public static class TestCoordsDeserialization
{
private class Coords
{
public Double X { get; set; }
public Double Y { get; set; }
public Double Z { get; set; }
public Double A { get; set; }
}
private class Engine
{
public string Text { get; set; }
public int Id { get; set; }
public Coords[] Outs { get; protected set; }
public Engine()
{
this.Outs = new Coords[3];
for (int i = 0; i < this.Outs.Length; i++)
{
this.Outs[i] = new Coords();
}
}
}
public static void Test()
{
Engine e = new Engine();
e.Id = 42;
e.Text = "MyText";
e.Outs[0] = new Coords() { A = 0, X = 10, Y = 11, Z = 0 };
e.Outs[1] = new Coords() { A = 0, X = 20, Y = 22, Z = 0 };
e.Outs[2] = new Coords() { A = 0, X = 30, Y = 33, Z = 0 };
string json = JsonConvert.SerializeObject(e);
Console.WriteLine(json); //{"Text":"MyText","Id":42,"Positions":{"Test":9,"Outs":[{"X":10.0,"Y":11.0,"Z":0.0,"A":0.0},{"X":20.0,"Y":22.0,"Z":0.0,"A":0.0},{"X":30.0,"Y":33.0,"Z":0.0,"A":0.0}]}}
Engine r = JsonConvert.DeserializeObject<Engine>(json);
double value = r.Outs[1].X; // should be '20.0'
Console.WriteLine(value);
Debugger.Break();
}
}
How can I make value
to be 20.0?
Try this:
var contractResolver = new DefaultContractResolver();
contractResolver.DefaultMembersSearchFlags |= BindingFlags.NonPublic;
Engine r = JsonConvert.DeserializeObject<Engine>(json), new JsonSerializerSettings
{
ContractResolver = contractResolver
});
Using above-mentioned code you will get the follwoing Warning message:
'DefaultContractResolver.DefaultMembersSearchFlags' is obsolete: 'DefaultMembersSearchFlags is obsolete. To modify the members serialized inherit from DefaultContractResolver and override the GetSerializableMembers method instead.'
To solve it you can use the following solution instead:
Create a class that inherits from DefaultContractResolver
to get the non public properties:
public class CustomContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{
var prop = base.CreateProperty(member, memberSerialization);
if (!prop.Writable)
{
var property = member as PropertyInfo;
if (property != null)
{
var hasNonPublicSetter = property.GetSetMethod(true) != null;
prop.Writable = hasNonPublicSetter;
}
}
return prop;
}
}
And finally use it as follow:
var contractResolver = new CustomContractResolver();
Engine r = JsonConvert.DeserializeObject<Engine>(json), new JsonSerializerSettings
{
ContractResolver = contractResolver
});
Mark Outs
with the [JsonProperty]
attribute:
private class Engine
{
public string Text { get; set; }
public int Id { get; set; }
[JsonProperty] // Causes the protected setter to be called on deserialization.
public Coords[] Outs { get; protected set; }
public Engine()
{
this.Outs = new Coords[3];
for (int i = 0; i < this.Outs.Length; i++)
{
this.Outs[i] = new Coords();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With