I have the following class:
public sealed class SomeClass
{
[JsonConstructor()]
public SomeClass(IEnumerable<string> myItems)
{
InternalMyItems = new Collection<string>(myItems.ToArray());
MyItems = new ReadOnlyCollection<string>(InternalMyItems);
}
public IReadOnlyCollection<string> MyItems { get; }
private Collection<string> InternalMyItems { get; }
}
Serialization seems to work fine:
{
"MyItems": [
"A",
"B",
"C"
]
}
Deserialization doesn’t seem to work. Ideally, I’d like to stick to using ReadOnlyCollection<T>
and Collection<T>
and not have to change to some other types. This sample code throws an exception when attempting to deserialize:
var options = new JsonSerializerOptions()
{
WriteIndented = true
};
var items = new[] { "A", "B", "C" };
var instance = new SomeClass(items);
var json = JsonSerializer.Serialize(instance, options);
var copy = JsonSerializer.Deserialize<SomeClass>(json, options);
InvalidOperationException: Each parameter in the deserialization
constructor on type ‘UserQuery+SomeClass’ must bind to an object
property or field on deserialization. Each parameter name must match
with a property or field on the object. Fields are only considered
when ‘JsonSerializerOptions.IncludeFields’ is enabled. The match can
be case-insensitive.
Here is a .NET Fiddle example of the code running and giving an error: https://dotnetfiddle.net/vorOLX
2
Answers
The type and name of constructor parameters must match the properties in the class. System.Text.Json also knows how to construct a
IReadOnlyCollection<T>
directly, so just use that type. For example, you could simply do this:From the docs:
You can try using
IReadOnlyCollection
and match the types:If needed you can keep the original ctor: