gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 21:38:40 27 4
gpt4 key购买 nike

我正在使用 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 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 来填补空白。

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

最佳答案

My best guess is that the deserializer is keeping track of which properties can be set via the constructor (by some convention, since casing seems to be ignored), and then uses property setters where possible to fill in the gaps.Is this the way it works?

是的,这就是要点。如果你看一下 source code你可以自己看看。在 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实用方法,如果您有兴趣。

Are the order of operations/rules for deserialization documented somewhere?

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

关于c# - Json.Net 反序列化构造函数与属性规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33107789/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com