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

Phi*_*ler 6 c# serialization json json.net

我正在使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

但是,我想要更好地理解这一点,所以我恢复了代码并在将两个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用和不使用默认构造函数(显示的代码省略了默认构造函数).

使用默认构造函数:调用默认构造函数,然后调用两个属性设置器.

如果没有默认构造函数:调用非默认构造函数,则调用WithDrawlDate setter.永远不会调用NumberOfCoinsByType setter.

我最好的猜测是反序列化器跟踪可以通过构造函数设置哪些属性(通过某种约定,因为似乎忽略了大小写),然后在可能的情况下使用属性设置器来填补空白.

这是它的工作方式吗?是否在某处记录了反序列化的操作顺序/规则?

Bri*_*ers 5

我最好的猜测是,解串器正在跟踪可以通过构造函数设置哪些属性(按照惯例,因为似乎忽略了大小写),然后在可能的情况下使用属性设置器。这是它的工作方式吗?

是的,这几乎是要点。如果您查看源代码,就可以自己看到。在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);

...
Run Code Online (Sandbox Code Playgroud)

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

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

据我所知。官方文档在这里,但是没有详细介绍。