Json.网络反序列化构造函数与属性规则

本文关键字:属性 规则 构造函数 网络 反序列化 Json | 更新日期: 2023-09-27 18:17:34

我正在使用Json排除以下类的(反)序列化问题。净:

public class CoinsWithdrawn
{
    public DateTimeOffset WithdrawlDate { get; private set; }
    public Dictionary<CoinType, int> NumberOfCoinsByType { get; private set; }
    public CoinsWithdrawn(DateTimeOffset withdrawDate, Dictionary<CoinType, int> numberOfCoinsByType)
    {
        WithdrawlDate = withdrawDate;
        NumberOfCoinsByType = numberOfCoinsByType;
    }
}

问题是构造函数参数"withdrawDate"的命名与属性名称"withdrawDate"不同。使名字匹配(甚至忽略大小写)修复了这个问题。

然而,我想更好地理解这一点,所以我还原了代码并在将两个setter都设置为公共后进行了测试。这也解决了这个问题。

最后,我从自动属性切换到带支持字段的属性,这样我就可以完全调试并看到实际发生了什么:

public class CoinsWithdrawn
{
    private DateTimeOffset _withdrawlDate;
    private Dictionary<CoinType, int> _numberOfCoinsByType;
    public DateTimeOffset WithdrawlDate
    {
        get { return _withdrawlDate; }
        set { _withdrawlDate = value; }
    }
    public Dictionary<CoinType, int> NumberOfCoinsByType
    {
        get { return _numberOfCoinsByType; }
        set { _numberOfCoinsByType = value; }
    }
    public CoinsWithdrawn(DateTimeOffset withdrawDate, Dictionary<CoinType, int> numberOfCoinsByType)
    {
        WithdrawlDate = withdrawDate;
        NumberOfCoinsByType = numberOfCoinsByType;
    }
}

我在有默认构造函数和没有默认构造函数的情况下尝试了这个(所示的代码省略了默认构造函数)。

使用默认构造函数:调用默认构造函数,则调用两个属性setter。

没有默认构造函数:调用非默认构造函数,然后调用抽出日期设置器。NumberOfCoinsByType setter永远不会被调用。

我最好的猜测是,反序列化器正在跟踪可以通过构造函数设置哪些属性(根据某种惯例,因为大小写似乎被忽略了),然后在可能的地方使用属性设置器来填补空白。

它是这样工作的吗?反序列化的操作顺序/规则是否有文档记录?

Json.网络反序列化构造函数与属性规则

我最好的猜测是,反序列化器正在跟踪可以通过构造函数设置哪些属性(根据某种惯例,因为大小写似乎被忽略了),然后在可能的地方使用属性设置器来填补空白。这就是它的运作方式吗?

是的,这就是要点。如果您看一下源代码,您可以自己看到。在JsonSerializerInternalReader类中有一个方法CreateObjectUsingCreatorWithParameters,它使用非默认构造函数处理对象的实例化。我把相关的部分复制到了下面。

ResolvePropertyAndCreatorValues方法从JSON中获取数据值,然后循环尝试将它们与构造函数参数相匹配。不匹配1的将被添加到remainingPropertyValues字典中。然后使用匹配的参数实例化对象,使用空/默认值填充任何空白。方法中稍后的第二个循环(此处未显示)然后尝试调用对象上的setter来获取该字典中剩余的属性。

IDictionary<JsonProperty, object> propertyValues = 
    ResolvePropertyAndCreatorValues(contract, containerProperty, reader, objectType, out extensionData);
object[] creatorParameterValues = new object[contract.CreatorParameters.Count];
IDictionary<JsonProperty, object> remainingPropertyValues = new Dictionary<JsonProperty, object>();
foreach (KeyValuePair<JsonProperty, object> propertyValue in propertyValues)
{
    JsonProperty property = propertyValue.Key;
    JsonProperty matchingCreatorParameter;
    if (contract.CreatorParameters.Contains(property))
    {
        matchingCreatorParameter = property;
    }
    else
    {
        // check to see if a parameter with the same name as the underlying property name exists and match to that
        matchingCreatorParameter = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, property.UnderlyingName);
    }
    if (matchingCreatorParameter != null)
    {
        int i = contract.CreatorParameters.IndexOf(matchingCreatorParameter);
        creatorParameterValues[i] = propertyValue.Value;
    }
    else
    {
        remainingPropertyValues.Add(propertyValue);
    }
    ...
} 
...
object createdObject = creator(creatorParameterValues);
...

1参数匹配算法本质上是一个不区分大小写的搜索,如果找到多个匹配,则返回到区分大小写。如果您感兴趣,请查看ForgivingCaseSensitiveFind实用程序方法。

反序列化的操作顺序/规则是否记录在某处?

据我所知没有。官方文档在这里,但它没有进入这个级别的细节。