How to deserialize a read only List with Json.Net
I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.
I expose
AddItem(Item x)
and a
IEnumerable<Item> Items
get // returns a projection of internal list
Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.
How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?
c# serialization json.net deserialization
add a comment |
I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.
I expose
AddItem(Item x)
and a
IEnumerable<Item> Items
get // returns a projection of internal list
Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.
How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?
c# serialization json.net deserialization
did you triedvar list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented);?
– Kiquenet
Feb 5 '15 at 8:11
@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.
– Neil N
Feb 5 '15 at 16:58
@NeilN What worked for you?
– Prakhar
May 10 '16 at 9:34
add a comment |
I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.
I expose
AddItem(Item x)
and a
IEnumerable<Item> Items
get // returns a projection of internal list
Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.
How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?
c# serialization json.net deserialization
I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.
I expose
AddItem(Item x)
and a
IEnumerable<Item> Items
get // returns a projection of internal list
Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.
How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?
c# serialization json.net deserialization
c# serialization json.net deserialization
edited Mar 22 '17 at 19:07
Neil N
asked Dec 9 '14 at 19:20
Neil NNeil N
19.4k1474128
19.4k1474128
did you triedvar list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented);?
– Kiquenet
Feb 5 '15 at 8:11
@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.
– Neil N
Feb 5 '15 at 16:58
@NeilN What worked for you?
– Prakhar
May 10 '16 at 9:34
add a comment |
did you triedvar list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented);?
– Kiquenet
Feb 5 '15 at 8:11
@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.
– Neil N
Feb 5 '15 at 16:58
@NeilN What worked for you?
– Prakhar
May 10 '16 at 9:34
did you tried
var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?– Kiquenet
Feb 5 '15 at 8:11
did you tried
var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?– Kiquenet
Feb 5 '15 at 8:11
@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.
– Neil N
Feb 5 '15 at 16:58
@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.
– Neil N
Feb 5 '15 at 16:58
@NeilN What worked for you?
– Prakhar
May 10 '16 at 9:34
@NeilN What worked for you?
– Prakhar
May 10 '16 at 9:34
add a comment |
5 Answers
5
active
oldest
votes
What worked for me was the following:
[JsonProperty(PropertyName = "TargetName")]
private List<SomeClass> _SomeClassList get; set;
public IReadOnlyList<SomeClass> SomeClassList
get
return this._SomeClassList.AsReadOnly();
Then, make a function to prevent SomeClassList to be serialized:
public bool ShouldSerializeSomeClassList() return false;
1
I think this should be the accepted answer. Also, you can simply use[JsonIgnore]attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.
– bazsibazsi
Nov 14 '18 at 10:40
add a comment |
It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:
void Main()
Poco p = new Poco();
p.Items.Add("foo");
p.Items.Add("bar");
p.Dump(); // Linqpad command to show a visual objet dump in the output pane
String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );
serialized.Dump();
// serialized == ""Items":["foo","bar"]"
Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );
p2.Dump();
class Poco
public List<String> Items get; = new List<String>();
When I run this, the dumps of p and p2 are identical.
3
Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can writep2.Items.Add("foobar");after deserialisation..
– Jamey
Oct 24 '17 at 9:24
add a comment |
With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.
The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.
Any custom logic can be implemented inside AddItem.
The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings
public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>
public override bool CanConvert(Type objectType)
return typeof(ItemsHolder).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
JObject jObject = JObject.Load(reader);
ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;
var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
foreach (var jItem in jItems)
var childReader = CreateReaderFromToken(reader, jItem);
var item = serializer.Deserialize<Item>(childReader);
holder.AddItem(item);
return holder;
public override ItemsHolder Create(Type objectType)
return new ItemsHolder();
public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)
JsonReader jObjectReader = token.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateFormatString = reader.DateFormatString;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
jObjectReader.MaxDepth = reader.MaxDepth;
jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
return jObjectReader;
add a comment |
Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.
One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.
Here's my class that I'd like to Serialize/Deserialize
public class CannotDeserializeThis
private readonly IList<User> _users = new List<User>();
public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();
public void AddUser(User user)
_users.Add(user);
I could serialize this to:
"Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]
But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:
public class ReadonlyJsonDefaultContractResolver : 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 hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
if (!prop.Writable)
var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));
if (privateField != null)
var originalPropertyName = prop.PropertyName;
prop = base.CreateProperty(privateField, memberSerialization);
prop.Writable = true;
prop.PropertyName = originalPropertyName;
prop.UnderlyingName = originalPropertyName;
prop.Readable = true;
return prop;
The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.
This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')
add a comment |
I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:
public class State
[Newtonsoft.Json.JsonProperty]
public double Citizens get; private set;
[Newtonsoft.Json.JsonProperty]
public float Value get return pValue;
private float pValue = 450000.0f;
public List<string> BeachList get; = new List<string>();
public State()
public State(double _Citizens)
this.Citizens = _Citizens;
...
State croatia = new State(30.0D);
croatia.BeachList.Add("Bol na Braču");
croatia.BeachList.Add("Zrće");
string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);
State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);
So, croatia and, slovenia now both have the same property values.
I added Citizens and, Value properties to see if you want to work with one or the other way.
Thanks to Saeb Amini (Private setters in Json.Net)
My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"
– Neil N
Jul 5 '17 at 14:00
You're right about that. I will get to bottom of this. I will get back here @NeilN.
– MaGnumX
Jul 5 '17 at 18:38
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f27387085%2fhow-to-deserialize-a-read-only-list-with-json-net%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
What worked for me was the following:
[JsonProperty(PropertyName = "TargetName")]
private List<SomeClass> _SomeClassList get; set;
public IReadOnlyList<SomeClass> SomeClassList
get
return this._SomeClassList.AsReadOnly();
Then, make a function to prevent SomeClassList to be serialized:
public bool ShouldSerializeSomeClassList() return false;
1
I think this should be the accepted answer. Also, you can simply use[JsonIgnore]attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.
– bazsibazsi
Nov 14 '18 at 10:40
add a comment |
What worked for me was the following:
[JsonProperty(PropertyName = "TargetName")]
private List<SomeClass> _SomeClassList get; set;
public IReadOnlyList<SomeClass> SomeClassList
get
return this._SomeClassList.AsReadOnly();
Then, make a function to prevent SomeClassList to be serialized:
public bool ShouldSerializeSomeClassList() return false;
1
I think this should be the accepted answer. Also, you can simply use[JsonIgnore]attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.
– bazsibazsi
Nov 14 '18 at 10:40
add a comment |
What worked for me was the following:
[JsonProperty(PropertyName = "TargetName")]
private List<SomeClass> _SomeClassList get; set;
public IReadOnlyList<SomeClass> SomeClassList
get
return this._SomeClassList.AsReadOnly();
Then, make a function to prevent SomeClassList to be serialized:
public bool ShouldSerializeSomeClassList() return false;
What worked for me was the following:
[JsonProperty(PropertyName = "TargetName")]
private List<SomeClass> _SomeClassList get; set;
public IReadOnlyList<SomeClass> SomeClassList
get
return this._SomeClassList.AsReadOnly();
Then, make a function to prevent SomeClassList to be serialized:
public bool ShouldSerializeSomeClassList() return false;
answered Apr 28 '15 at 11:46
WotuuWotuu
5421517
5421517
1
I think this should be the accepted answer. Also, you can simply use[JsonIgnore]attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.
– bazsibazsi
Nov 14 '18 at 10:40
add a comment |
1
I think this should be the accepted answer. Also, you can simply use[JsonIgnore]attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.
– bazsibazsi
Nov 14 '18 at 10:40
1
1
I think this should be the accepted answer. Also, you can simply use
[JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.– bazsibazsi
Nov 14 '18 at 10:40
I think this should be the accepted answer. Also, you can simply use
[JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.– bazsibazsi
Nov 14 '18 at 10:40
add a comment |
It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:
void Main()
Poco p = new Poco();
p.Items.Add("foo");
p.Items.Add("bar");
p.Dump(); // Linqpad command to show a visual objet dump in the output pane
String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );
serialized.Dump();
// serialized == ""Items":["foo","bar"]"
Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );
p2.Dump();
class Poco
public List<String> Items get; = new List<String>();
When I run this, the dumps of p and p2 are identical.
3
Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can writep2.Items.Add("foobar");after deserialisation..
– Jamey
Oct 24 '17 at 9:24
add a comment |
It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:
void Main()
Poco p = new Poco();
p.Items.Add("foo");
p.Items.Add("bar");
p.Dump(); // Linqpad command to show a visual objet dump in the output pane
String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );
serialized.Dump();
// serialized == ""Items":["foo","bar"]"
Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );
p2.Dump();
class Poco
public List<String> Items get; = new List<String>();
When I run this, the dumps of p and p2 are identical.
3
Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can writep2.Items.Add("foobar");after deserialisation..
– Jamey
Oct 24 '17 at 9:24
add a comment |
It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:
void Main()
Poco p = new Poco();
p.Items.Add("foo");
p.Items.Add("bar");
p.Dump(); // Linqpad command to show a visual objet dump in the output pane
String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );
serialized.Dump();
// serialized == ""Items":["foo","bar"]"
Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );
p2.Dump();
class Poco
public List<String> Items get; = new List<String>();
When I run this, the dumps of p and p2 are identical.
It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:
void Main()
Poco p = new Poco();
p.Items.Add("foo");
p.Items.Add("bar");
p.Dump(); // Linqpad command to show a visual objet dump in the output pane
String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );
serialized.Dump();
// serialized == ""Items":["foo","bar"]"
Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );
p2.Dump();
class Poco
public List<String> Items get; = new List<String>();
When I run this, the dumps of p and p2 are identical.
answered May 22 '17 at 5:44
DaiDai
72.5k13115201
72.5k13115201
3
Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can writep2.Items.Add("foobar");after deserialisation..
– Jamey
Oct 24 '17 at 9:24
add a comment |
3
Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can writep2.Items.Add("foobar");after deserialisation..
– Jamey
Oct 24 '17 at 9:24
3
3
Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write
p2.Items.Add("foobar"); after deserialisation..– Jamey
Oct 24 '17 at 9:24
Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write
p2.Items.Add("foobar"); after deserialisation..– Jamey
Oct 24 '17 at 9:24
add a comment |
With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.
The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.
Any custom logic can be implemented inside AddItem.
The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings
public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>
public override bool CanConvert(Type objectType)
return typeof(ItemsHolder).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
JObject jObject = JObject.Load(reader);
ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;
var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
foreach (var jItem in jItems)
var childReader = CreateReaderFromToken(reader, jItem);
var item = serializer.Deserialize<Item>(childReader);
holder.AddItem(item);
return holder;
public override ItemsHolder Create(Type objectType)
return new ItemsHolder();
public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)
JsonReader jObjectReader = token.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateFormatString = reader.DateFormatString;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
jObjectReader.MaxDepth = reader.MaxDepth;
jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
return jObjectReader;
add a comment |
With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.
The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.
Any custom logic can be implemented inside AddItem.
The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings
public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>
public override bool CanConvert(Type objectType)
return typeof(ItemsHolder).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
JObject jObject = JObject.Load(reader);
ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;
var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
foreach (var jItem in jItems)
var childReader = CreateReaderFromToken(reader, jItem);
var item = serializer.Deserialize<Item>(childReader);
holder.AddItem(item);
return holder;
public override ItemsHolder Create(Type objectType)
return new ItemsHolder();
public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)
JsonReader jObjectReader = token.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateFormatString = reader.DateFormatString;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
jObjectReader.MaxDepth = reader.MaxDepth;
jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
return jObjectReader;
add a comment |
With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.
The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.
Any custom logic can be implemented inside AddItem.
The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings
public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>
public override bool CanConvert(Type objectType)
return typeof(ItemsHolder).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
JObject jObject = JObject.Load(reader);
ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;
var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
foreach (var jItem in jItems)
var childReader = CreateReaderFromToken(reader, jItem);
var item = serializer.Deserialize<Item>(childReader);
holder.AddItem(item);
return holder;
public override ItemsHolder Create(Type objectType)
return new ItemsHolder();
public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)
JsonReader jObjectReader = token.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateFormatString = reader.DateFormatString;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
jObjectReader.MaxDepth = reader.MaxDepth;
jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
return jObjectReader;
With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.
The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.
Any custom logic can be implemented inside AddItem.
The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings
public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>
public override bool CanConvert(Type objectType)
return typeof(ItemsHolder).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
JObject jObject = JObject.Load(reader);
ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;
var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
foreach (var jItem in jItems)
var childReader = CreateReaderFromToken(reader, jItem);
var item = serializer.Deserialize<Item>(childReader);
holder.AddItem(item);
return holder;
public override ItemsHolder Create(Type objectType)
return new ItemsHolder();
public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)
JsonReader jObjectReader = token.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateFormatString = reader.DateFormatString;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
jObjectReader.MaxDepth = reader.MaxDepth;
jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
return jObjectReader;
answered Jul 20 '17 at 10:23
animalito maquinaanimalito maquina
1,16011126
1,16011126
add a comment |
add a comment |
Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.
One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.
Here's my class that I'd like to Serialize/Deserialize
public class CannotDeserializeThis
private readonly IList<User> _users = new List<User>();
public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();
public void AddUser(User user)
_users.Add(user);
I could serialize this to:
"Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]
But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:
public class ReadonlyJsonDefaultContractResolver : 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 hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
if (!prop.Writable)
var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));
if (privateField != null)
var originalPropertyName = prop.PropertyName;
prop = base.CreateProperty(privateField, memberSerialization);
prop.Writable = true;
prop.PropertyName = originalPropertyName;
prop.UnderlyingName = originalPropertyName;
prop.Readable = true;
return prop;
The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.
This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')
add a comment |
Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.
One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.
Here's my class that I'd like to Serialize/Deserialize
public class CannotDeserializeThis
private readonly IList<User> _users = new List<User>();
public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();
public void AddUser(User user)
_users.Add(user);
I could serialize this to:
"Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]
But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:
public class ReadonlyJsonDefaultContractResolver : 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 hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
if (!prop.Writable)
var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));
if (privateField != null)
var originalPropertyName = prop.PropertyName;
prop = base.CreateProperty(privateField, memberSerialization);
prop.Writable = true;
prop.PropertyName = originalPropertyName;
prop.UnderlyingName = originalPropertyName;
prop.Readable = true;
return prop;
The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.
This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')
add a comment |
Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.
One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.
Here's my class that I'd like to Serialize/Deserialize
public class CannotDeserializeThis
private readonly IList<User> _users = new List<User>();
public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();
public void AddUser(User user)
_users.Add(user);
I could serialize this to:
"Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]
But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:
public class ReadonlyJsonDefaultContractResolver : 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 hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
if (!prop.Writable)
var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));
if (privateField != null)
var originalPropertyName = prop.PropertyName;
prop = base.CreateProperty(privateField, memberSerialization);
prop.Writable = true;
prop.PropertyName = originalPropertyName;
prop.UnderlyingName = originalPropertyName;
prop.Readable = true;
return prop;
The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.
This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')
Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.
One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.
Here's my class that I'd like to Serialize/Deserialize
public class CannotDeserializeThis
private readonly IList<User> _users = new List<User>();
public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();
public void AddUser(User user)
_users.Add(user);
I could serialize this to:
"Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]
But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:
public class ReadonlyJsonDefaultContractResolver : 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 hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
if (!prop.Writable)
var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));
if (privateField != null)
var originalPropertyName = prop.PropertyName;
prop = base.CreateProperty(privateField, memberSerialization);
prop.Writable = true;
prop.PropertyName = originalPropertyName;
prop.UnderlyingName = originalPropertyName;
prop.Readable = true;
return prop;
The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.
This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')
edited Nov 29 '18 at 18:00
answered Nov 28 '18 at 16:50
Jay DubyaJay Dubya
114
114
add a comment |
add a comment |
I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:
public class State
[Newtonsoft.Json.JsonProperty]
public double Citizens get; private set;
[Newtonsoft.Json.JsonProperty]
public float Value get return pValue;
private float pValue = 450000.0f;
public List<string> BeachList get; = new List<string>();
public State()
public State(double _Citizens)
this.Citizens = _Citizens;
...
State croatia = new State(30.0D);
croatia.BeachList.Add("Bol na Braču");
croatia.BeachList.Add("Zrće");
string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);
State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);
So, croatia and, slovenia now both have the same property values.
I added Citizens and, Value properties to see if you want to work with one or the other way.
Thanks to Saeb Amini (Private setters in Json.Net)
My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"
– Neil N
Jul 5 '17 at 14:00
You're right about that. I will get to bottom of this. I will get back here @NeilN.
– MaGnumX
Jul 5 '17 at 18:38
add a comment |
I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:
public class State
[Newtonsoft.Json.JsonProperty]
public double Citizens get; private set;
[Newtonsoft.Json.JsonProperty]
public float Value get return pValue;
private float pValue = 450000.0f;
public List<string> BeachList get; = new List<string>();
public State()
public State(double _Citizens)
this.Citizens = _Citizens;
...
State croatia = new State(30.0D);
croatia.BeachList.Add("Bol na Braču");
croatia.BeachList.Add("Zrće");
string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);
State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);
So, croatia and, slovenia now both have the same property values.
I added Citizens and, Value properties to see if you want to work with one or the other way.
Thanks to Saeb Amini (Private setters in Json.Net)
My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"
– Neil N
Jul 5 '17 at 14:00
You're right about that. I will get to bottom of this. I will get back here @NeilN.
– MaGnumX
Jul 5 '17 at 18:38
add a comment |
I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:
public class State
[Newtonsoft.Json.JsonProperty]
public double Citizens get; private set;
[Newtonsoft.Json.JsonProperty]
public float Value get return pValue;
private float pValue = 450000.0f;
public List<string> BeachList get; = new List<string>();
public State()
public State(double _Citizens)
this.Citizens = _Citizens;
...
State croatia = new State(30.0D);
croatia.BeachList.Add("Bol na Braču");
croatia.BeachList.Add("Zrće");
string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);
State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);
So, croatia and, slovenia now both have the same property values.
I added Citizens and, Value properties to see if you want to work with one or the other way.
Thanks to Saeb Amini (Private setters in Json.Net)
I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:
public class State
[Newtonsoft.Json.JsonProperty]
public double Citizens get; private set;
[Newtonsoft.Json.JsonProperty]
public float Value get return pValue;
private float pValue = 450000.0f;
public List<string> BeachList get; = new List<string>();
public State()
public State(double _Citizens)
this.Citizens = _Citizens;
...
State croatia = new State(30.0D);
croatia.BeachList.Add("Bol na Braču");
croatia.BeachList.Add("Zrće");
string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);
State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);
So, croatia and, slovenia now both have the same property values.
I added Citizens and, Value properties to see if you want to work with one or the other way.
Thanks to Saeb Amini (Private setters in Json.Net)
answered Jul 3 '17 at 9:00
MaGnumXMaGnumX
30026
30026
My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"
– Neil N
Jul 5 '17 at 14:00
You're right about that. I will get to bottom of this. I will get back here @NeilN.
– MaGnumX
Jul 5 '17 at 18:38
add a comment |
My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"
– Neil N
Jul 5 '17 at 14:00
You're right about that. I will get to bottom of this. I will get back here @NeilN.
– MaGnumX
Jul 5 '17 at 18:38
My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"
– Neil N
Jul 5 '17 at 14:00
My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"
– Neil N
Jul 5 '17 at 14:00
You're right about that. I will get to bottom of this. I will get back here @NeilN.
– MaGnumX
Jul 5 '17 at 18:38
You're right about that. I will get to bottom of this. I will get back here @NeilN.
– MaGnumX
Jul 5 '17 at 18:38
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f27387085%2fhow-to-deserialize-a-read-only-list-with-json-net%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
did you tried
var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented);?– Kiquenet
Feb 5 '15 at 8:11
@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.
– Neil N
Feb 5 '15 at 16:58
@NeilN What worked for you?
– Prakhar
May 10 '16 at 9:34