Matthias Müller
Matthias Müller

Reputation: 3483

Deserialization causes copies of List-Entries

I'd like to create a very general Model-Layer, which can also be passed arround as JSON. One Model should show a LED-Panel of a RaspberryPi2. Since I'd like to model the Class to be as near as possible to the reality, I force a List to always have 8 * 8 Leds. The Class is looking like this:

public class VisualLedPanel
{
    private readonly Lazy<List<VisualLed>> _lazyVisualLeds = new Lazy<List<VisualLed>>(CreateVisualLeds);

    public VisualLed this[int x, int y]
    {
        get
        {
            var result = VisualLeds.FirstOrDefault(f => f.X == x && f.Y == y);
            return result;
        }
    }

    public IEnumerable<VisualLed> VisualLeds
    {
        get
        {
            return _lazyVisualLeds.Value;
        }
        set
        {
            var tt = value;
        }
    }

    private static List<VisualLed> CreateVisualLeds()
    {
        var result = new List<VisualLed>();
        for (var x = 0; x <= 7; x++)
        {
            for (var y = 0; y <= 7; y++)
            {
                result.Add(new VisualLed(x, y));
            }
        }

        return result;
    }
}

The problem arises with the Serialization: I'm using the NewtonSoft. Json.Net Serializer, and as far as I've seen, it first accesses the Getter, which causes the Logic to create the Leds, and then sets them afterwards. The only solution I could think of would either be a Custom-Deserializer or some sort of Constructor shennenigans. It also seems like the Deserializer doesn't use the Set-Property of the VisualLeds-Value, since my Debugger-Stop never was hitted.

Is there an easy possibility arround to have the best of both worlds? I'd like to have the Model as general as possible without the need of Custom-Deserializer.

Upvotes: 3

Views: 132

Answers (1)

dbc
dbc

Reputation: 116991

The easiest way for you to do this without having to write your own custom JsonConverter will be to serialize your collection of VisualLed objects as a proxy array property, marking the original property as ignored:

public class VisualLedPanel
{
    private readonly Lazy<List<VisualLed>> _lazyVisualLeds = new Lazy<List<VisualLed>>(CreateVisualLeds);

    public VisualLed this[int x, int y]
    {
        get
        {
            var result = VisualLeds.FirstOrDefault(f => f.X == x && f.Y == y);
            return result;
        }
    }

    [JsonIgnore]
    public IEnumerable<VisualLed> VisualLeds
    {
        get
        {
            return _lazyVisualLeds.Value;
        }
    }


    [JsonProperty("VisualLeds")]
    VisualLed [] SerializableVisualLeds
    {
        get
        {
            return VisualLeds.ToArray();

        }
        set
        {
            if (value == null || value.Length == 0)
            {
                if (_lazyVisualLeds.IsValueCreated)
                    _lazyVisualLeds.Value.Clear();
            }
            else
            {
                _lazyVisualLeds.Value.Clear();
                _lazyVisualLeds.Value.AddRange(value);
            }
        }
    }

    private static List<VisualLed> CreateVisualLeds()
    {
        var result = new List<VisualLed>();
        for (var x = 0; x <= 7; x++)
        {
            for (var y = 0; y <= 7; y++)
            {
                result.Add(new VisualLed(x, y));
            }
        }

        return result;
    }
}

Prototype fiddle

For a further discussion, see Why are all the collections in my POCO are null when deserializing some valid json with the .NET Newtonsoft.Json component. Using ObjectCreationHandling.Replace would not be appropriate in this case since you want your Lazy<List<VisualLed>> _lazyVisualLeds to be read-only.

Upvotes: 2

Related Questions