-2

Supposing I have this immutable struct:

public struct LogGroup
{
    public Log<LowResolutionLogData> LowResolutionLog { get; }

    public IEnumerable<Log<MediumResolutionLogData>> MediumResolutionLogs { get; }

    public IEnumerable<Log<HighResolutionLogData>> HighResolutionLogs { get; }

    public LogGroup
    (
        Log<LowResolutionLogData> lowResolutionLog,
        IEnumerable<Log<MediumResolutionLogData>> mediumResolutionLogs,
        IEnumerable<Log<HighResolutionLogData>> highResolutionLogs
    )
    {
        LowResolutionLog = lowResolutionLog;
        MediumResolutionLogs = mediumResolutionLogs;
        HighResolutionLogs = highResolutionLogs;
    }
}

How do I serialize it without having to making the IEnumerable<> properties some concrete type (e.g. an Array or List)?

How do I deserialize into it without having to make the properties all settable (I want it to call the assignment constructor I've created)?

The complex types on the object may also have their own complex types and IEnumerable<>s as immutable properties. Log<> is a class whilst the types it takes are all structs so deserialization using assignment constructors needs to work for both. One of these types has a large number of properties so I want to avoid boilerplate code and have the serialization/deserialization handled dynamically if possible.

Matt Arnold
  • 668
  • 2
  • 8
  • 21
  • 3
    I believe Newtonsoft JSON handles this out of the box as long as the constructor parameter names match the property names you should be good to go. – JSteward Nov 03 '20 at 16:01
  • Nice, I did just try JSON.NET but was having trouble getting the correct objects needed to read from / write to a file. Would you be able to give a quick example? – Matt Arnold Nov 03 '20 at 16:04
  • 1
    Agreed, Json.NET can deserialize using a non-default constructor. See: [How does JSON deserialization in C# work](https://stackoverflow.com/a/41871975/3744182) for the precise algorithm by which a constructor is chosen. However, if there are *multiple* parameterized constructors, then Json.NET has no built-in way to know which to use absent marking one with `[JsonConstructor]`. I.e. your `LogGroup` should deserialize fine, but more complex immutable types might not. – dbc Nov 03 '20 at 16:35
  • *I did just try JSON.NET but was having trouble getting the correct objects needed to read from / write to a file* -- then please share a [mcve]. Json.NET certainly can deserialize from a file, see https://www.newtonsoft.com/json/help/html/DeserializeWithJsonSerializerFromFile.htm and https://www.newtonsoft.com/json/help/html/SerializeWithJsonSerializerToFile.htm – dbc Nov 03 '20 at 16:37

1 Answers1

1

A big thanks to JSteward for pointing me in the right direction on this. All I needed was this to serialize my LogGroup and write it to a file.

using (var streamWriter = File.CreateText(filePath))
    new JsonSerializer().Serialize(streamWriter, myLogGroup);

and this to read it from a file and turn it back into a LogGroup:

using (var streamReader = File.OpenText(filePath))
    var myLogGroup = (LogGroup)new JsonSerializer().Deserialize(streamReader, typeof(LogGroup));

I also had to mark the assignment constructor for each struct with [JsonConstructor] in order for Deserialize to use it (otherwise the properties were receiving their default values).

All type abstraction was handled for serialization.

As a side note, I used a .tt design-time template to create each of my objects to reduce the maintenance overhead of having an assignment constructor (I generate the properties, constructor parameters and property assignments all from one source).

Matt Arnold
  • 668
  • 2
  • 8
  • 21
  • 2
    Loading a file into a string, then deserializing from the string, can have negative performance impacts when the file is large. Instead you can deserialize directly from a stream as shown in [Performance Tips: Optimize Memory Usage](https://www.newtonsoft.com/json/help/html/Performance.htm#MemoryUsage), [Deserialize JSON from a file](https://www.newtonsoft.com/json/help/html/DeserializeWithJsonSerializerFromFile.htm) and [Serialize JSON to a file](https://www.newtonsoft.com/json/help/html/SerializeWithJsonSerializerToFile.htm). – dbc Nov 03 '20 at 16:43
  • Code changed based upon the prior comment. – Matt Arnold Nov 03 '20 at 17:17