属性 setter Json 反序列化列表 <Bar>

Property setter within Json deserialization for a List<Bar>

在 System.Text.Json 中,“setter”在使用列表类型的属性时如何工作?这不是我所期望的,尤其是与 setter 相关的字符串示例。

我的意思是:

public class Program
{
    public static void Main()
    {
        var json = @"
            {
              ""doot"": ""bloop bloop"",
              ""bars"": 
              [
                {
                    ""id"": 1
                },
                {
                    ""id"": 2
                }
              ]
            }
        ";
        
        var obj = JsonSerializer.Deserialize<Foo>(json);
        Console.WriteLine($"obj.Doot: {obj.Doot}");
        
        if (obj.Bars == null)
            Console.WriteLine("Bars is null.");
        else
            Console.WriteLine($"obj.Bars.Count: {obj.Bars.Count}");
        
    }
    
    public class Foo
    {
        private string _doot;
        [JsonPropertyName("doot")]
        public string Doot
        {
            get => _doot;
            set
            {
                Console.WriteLine($"Setting Doot to {value}");
                _doot = value;
            }
        }
        
        private List<Bar> _bars;
        [JsonPropertyName("bars")]
        public List<Bar> Bars 
        {
            get => _bars;
            set
            {
                Console.WriteLine($"Bars Value count during setter: {value.Count}");
                _bars = value;
            }
        }
    }
    public class Bar
    {
        [JsonPropertyName("id")]
        public int Id {get;set;}
    }
}

输出:

Setting Doot to bloop bloop

Bars Value count during setter: 0

obj.Doot: bloop bloop

obj.Bars.Count: 2

在上面,当 Doot setter 触发时,value 的值被设置为支持字段 _doot。当 Bars setter 触发时,value 中有 something,但不是两个 Bar 实例,如下所示setter 中的 Console.WriteLine 语句报告计数为 0。

如果我需要根据 属性 Bars 中设置的值做一些逻辑,如果 value 没有信息,我该如何实现?

fiddle供参考:

https://dotnetfiddle.net/7z2O9S

编辑:

有人在别处向我指出(caschw 如果你在这里谢谢)列表可能被初始化为一个空列表,然后 list.Addlist.AddRange 可以在初始化后使用(我不清楚在 System.Text.Json) 的掩护下使用的是哪个);这意味着 setter 只会执行一次,除非我更改对列表的引用。这是有道理的,但是,每当 Bars 的集合发生变化时,我将如何连接到 运行 一些逻辑?

您编辑中的假设是正确的。列表反序列化的方式是首先创建列表对象,然后添加各个元素。如果您考虑 JSON 是如何工作的,那么解析器和反序列化器以这种方式工作是有意义的:

当解析器遇到 [ 时,它知道正在启动 JSON 数组。因此,当该对象要反序列化为 .NET 集合类型时,它此时已经可以创建该集合。毕竟,反序列化器知道它应该反序列化到的目标类型。

所以反序列化器创建了列表对象,然后开始反序列化里面的项目。在您的例子中,这些是 Bar 个对象。所以它构造那些,设置属性,并且——一旦对象完成——最终将它们添加到列表中。

您实际上可以在源代码中看到这一点。有许多集合转换器,具体取决于您拥有的目标类型,但它们都继承自 IEnumerableDefaultConverter,后者基本上具有 the behavior I described above. For List<T>, the actual work then happens in the ListOfTConverter,它基本上只是初始化一个新列表并为每个调用 Add项目。

If I needed to do some logic based on the values being set within the property Bars, how can I accomplish that if value does not have the information?

我认为你不应该。您应该将反序列化过程视为一个单独的操作,而不是对其进行干扰。我建议你之后再做,例如作为反序列化后的 post 处理步骤。