反序列化导致列表条目的复制。

3

我希望创建一个通用的模型层,可以作为JSON传递。一个模型应该展示树莓派2的LED面板。由于我希望将类模型尽可能地贴近现实,我强制要求列表始终具有8 * 8个LED灯。类如下:

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;
    }
}

问题出现在序列化上:我正在使用NewtonSoft.Json.Net序列化器,据我所见,它首先访问Getter,导致逻辑创建Leds,然后再设置它们。唯一的解决方案是自定义反序列化程序或某种构造函数技巧。似乎反序列化程序也没有使用VisualLeds-Value的Set-Property,因为我的Debugger-Stop从未触发。
有没有简单的方法可以兼顾两全?我希望模型尽可能通用,不需要自定义反序列化程序。

1
除非初始化VisualLed类非常昂贵,或者您的代码中存在一条路径,您不会访问VisualLeds属性(这似乎非常不可能,因为此类别无其他操作),否则懒惰初始化似乎不是正确的模式。 - Nick Bailey
嗯,你受伤了吗?我一直认为在并发问题上,安全第一比后悔莫及更重要。 - Matthias Müller
在构造函数中初始化将会同样是线程安全的。 - Nick Bailey
1个回答

2

如果您不想编写自己的自定义JsonConverter,最简单的方法是将VisualLed对象的集合序列化为代理数组属性,并将原始属性标记为忽略

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;
    }
}

原型演示

如需进一步讨论,请参见为什么使用.NET Newtonsoft.Json组件反序列化一些有效json时,我的POCO中的所有集合都为空?。在这种情况下,使用ObjectCreationHandling.Replace不适用,因为您希望Lazy<List<VisualLed>> _lazyVisualLeds是只读的。


那是一个非常好的解决方案,谢谢。我会尽快尝试。 - Matthias Müller
运行得非常好!就像Nick说的那样,甚至可能不需要使用Lazy,但我认为您的示例恰好展示了该类的意图。非常感谢。 - Matthias Müller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接