Json.Net反序列化构造函数和属性规则

8

我正在使用Json.Net解决以下类的(反)序列化问题:

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"与属性名"WithDrawlDate"不同。让这两个名字匹配(即使忽略大小写)可以解决问题。
然而,我想更好地理解这个问题,所以我撤销了代码,并测试了一下将两个setter都设置为public之后的效果。这也解决了问题。
最后,我从自动属性切换到带有后备字段的属性,以便我完全调试并看到实际发生了什么:
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方法。

不使用默认构造函数:首先调用非默认构造函数,然后调用WithDrawlDate的setter方法。NumberOfCoinsByType的setter方法从未被调用。

我猜测反序列化程序会记录哪些属性可以通过构造函数设置(根据某种约定,因为似乎大小写被忽略),然后在可能的情况下使用属性的setter方法来填补空缺。

这是它的工作方式吗?反序列化的操作顺序/规则在哪里有记录?

1个回答

7
我的最佳猜测是,反序列化程序通过某种约定(因为大小写似乎被忽略了)跟踪哪些属性可以通过构造函数设置,然后尽可能使用属性设置器填补空缺。这就是它的工作方式吗?
是的,基本上就是这样。如果你看一下源代码,你就会明白。在JsonSerializerInternalReader类中,有一个方法CreateObjectUsingCreatorWithParameters来处理使用非默认构造函数实例化对象的情况。我已经复制了相关部分如下。 ResolvePropertyAndCreatorValues 方法从 JSON 中提取数据值,然后循环尝试将它们与构造函数参数匹配。那些不匹配的1则添加到 remainingPropertyValues 字典中。然后使用匹配的参数实例化对象,并使用 null/默认值填充任何空缺。方法中稍后的第二个循环(此处未显示)然后尝试调用对象上的 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实用程序方法。

反序列化的操作/规则顺序有没有文档记录?

据我所知没有。官方文档在这里,但没有涉及到这个层面的细节。


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