The pull request #34675 added support for private setters. And the default value for IgnoreReadOnlyProperties is false. So I would have assumed something like: [JsonInclude] public ObservableCollection<int> MyInt { get; } = new ObservableCollection<int>(); would work but it does not. It still requires the private set; to explicit written.
class Program
{
public static JsonSerializerOptions Options => new JsonSerializerOptions {IgnoreReadOnlyProperties = false};
static void Main(string[] args)
{
var readonlySetter = new MyClass_Readonly();
readonlySetter.MyInt.Add(1);
var readonlyJson = JsonSerializer.Serialize(readonlySetter);
Console.WriteLine("Readonly JSON: " + readonlyJson);
var newReadonlySetter = JsonSerializer.Deserialize<MyClass_Readonly>(readonlyJson);
Console.WriteLine("Readonly List Count: " + newReadonlySetter.MyInt.Count);
var privateSetter = new MyClass_PrivateSetter();
privateSetter.MyInt.Add(1);
var privateJson = JsonSerializer.Serialize(privateSetter);
Console.WriteLine("Private JSON: " + privateJson);
var newPrivateSetter = JsonSerializer.Deserialize<MyClass_PrivateSetter>(privateJson);
Console.WriteLine("Private List Count: " + newPrivateSetter.MyInt.Count);
}
}
class MyClass_Readonly
{
[JsonInclude] public ObservableCollection<int> MyInt { get; } = new ObservableCollection<int>();
}
class MyClass_PrivateSetter
{
[JsonInclude] public ObservableCollection<int> MyInt { get; private set; } = new ObservableCollection<int>();
}
Output:
Readonly JSON: {"MyInt":[1]}
Readonly List Count: 0
Private JSON: {"MyInt":[1]}
Private List Count: 1
I would think this behavior would be by design. A property defined as "{ get; }" doesn't have a private setter. It has literally _no setter at all_. There's nothing that can be reflection invoked.
Yes it would be a read-only property then. But guess what, IgnoreReadOnlyProperties is set to false. So I would think it would include read-only properties then, right? Might be a bug with private setter or with readonly properties. Both are now supported but in my example it just don't work.
_FYI: In Newtonsoft JSON it works out of the box. Just saying in case you would think it would be technically impossible, it is not_
FYI: In Newtonsoft JSON it works out of the box. Just saying in case you would think it would be technically impossible, it is not
It doesn't, according to this: https://github.com/JamesNK/Newtonsoft.Json/issues/703.
FYI: In Newtonsoft JSON it works out of the box. Just saying in case you would think it would be technically impossible, it is not
It doesn't, according to this: JamesNK/Newtonsoft.Json#703.
If you would have taken my example and ran it with Newtonsoft you would have noticed it does
class Program
{
static void Main(string[] args)
{
var readonlySetter = new MyClass_Readonly();
readonlySetter.MyInt.Add(1);
var readonlyJson = JsonConvert.SerializeObject(readonlySetter);
Console.WriteLine("Readonly JSON: " + readonlyJson);
var newReadonlySetter = JsonConvert.DeserializeObject<MyClass_Readonly>(readonlyJson);
Console.WriteLine("Readonly List Count: " + newReadonlySetter.MyInt.Count);
var privateSetter = new MyClass_PrivateSetter();
privateSetter.MyInt.Add(1);
var privateJson = JsonConvert.SerializeObject(privateSetter);
Console.WriteLine("Private JSON: " + privateJson);
var newPrivateSetter = JsonConvert.DeserializeObject<MyClass_PrivateSetter>(privateJson);
Console.WriteLine("Private List Count: " + newPrivateSetter.MyInt.Count);
}
}
class MyClass_Readonly
{
[JsonProperty("a", DefaultValueHandling = DefaultValueHandling.Include)] public ObservableCollection<int> MyInt { get; } = new ObservableCollection<int>();
}
class MyClass_PrivateSetter
{
[JsonProperty("b", DefaultValueHandling = DefaultValueHandling.Include)] public ObservableCollection<int> MyInt { get; private set; } = new ObservableCollection<int>();
}
=== Output ===
Readonly JSON: {"a":[1]}
Readonly List Count: 1
Private JSON: {"b":[1]}
Private List Count: 1
Also this side note does not change my actual issue about both readonly and private setters are officially supported but practically it doesn't work. So let's keep focusing on System.Text.Json instead of Newtonsoft for now.
I see - you don't want to be able to actually set readonly properties, but to populate existing collections with deserialized data. (I assume Newtonsoft doesn't actually set the readonly property in your sample, but clears the collection and adds new items to it to sidestep problems discussed at length in the Newtonsoft issue.)
Yes exactly! 馃憤 I want the property to be a new collection with all the data from the deserialization (and if there is no data, it leaves the default behavior) I'm sorry, if I was misleading about this.
I've updated the issue title to more accurately reflect what's being requested.
This is a duplicate of https://github.com/dotnet/runtime/issues/30258.
Most helpful comment
I see - you don't want to be able to actually set readonly properties, but to populate existing collections with deserialized data. (I assume Newtonsoft doesn't actually set the readonly property in your sample, but clears the collection and adds new items to it to sidestep problems discussed at length in the Newtonsoft issue.)