Although you cannot serialize a private field directly as is, you can do it indirectly.
You need to provide a public property for the field and a constructor as in the following example:
class MyNumbers
{
// This private field will not be serialized
private List<int> _numbers;
// This public property will be serialized
public IEnumerable<int> Numbers => _numbers;
// The serialized property will be recovered with this dedicated constructor
// upon deserialization. Type and name must be the same as the public property.
public MyNumbers(IEnumerable<int> Numbers = null)
{
_numbers = Numbers as List<int> ?? Numbers?.ToList() ?? new();
}
}
The following code demonstrates how that works:
string json;
// Serialization
{
MyNumbers myNumbers = new(new List<int> { 10, 20, 30});
json = JsonSerializer.Serialize(myNumbers);
Console.WriteLine(json);
}
// Deserialization
{
var myNumbers2 = JsonSerializer.Deserialize<MyNumbers>(json);
foreach (var number in myNumbers2.Numbers)
Console.Write(number + " ");
}
Output:
{"Numbers":[10,20,30]}
10 20 30
If you want to detract people from accessing your private data, you can change the name to something explicitly forbidden like __private_numbers.
class MyNumbers2
{
private List<int> _numbers;
public IEnumerable<int> __private_numbers => _numbers;
public MyNumbers2(IEnumerable<int> __private_numbers = null)
{
_numbers = __private_numbers as List<int> ?? __private_numbers?.ToList() ?? new();
}
}
If an external coder is fool enough to access that private data as if it was part of the normal programming interface of that class, then shame on him. You are in your plain right to change that "private interface" without any guilt. And he can't mess with your internal list either, with an IEnumerable.
In most situations, that should be enough.