我使用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;
}
}
我尝试使用和不使用默认构造函数(显示的代码省略了默认构造函数)。
使用默认构造函数:调用默认构造函数,然后调用两个属性设置器。
没有默认构造函数:调用非默认构造函数,然后调用WithDrawlDate setter。永远不会调用NumberOfCoinsByType setter。
我最好的猜测是反序列化器跟踪可以通过构造函数设置哪些属性(通过某些约定,因为似乎忽略了大小写),然后在可能的情况下使用属性设置器来填补空白。
这是它的工作方式吗?是否在某处记录了反序列化的操作顺序/规则?
答案 0 :(得分:3)
我最好的猜测是反序列化器跟踪可以通过构造函数设置哪些属性(通过某些约定,因为似乎忽略了大小写),然后在可能的情况下使用属性设置器来填补空白。 这是它的工作方式吗?
是的,这几乎就是要点。如果您看一下自己可以看到的source code。在JsonSerializerInternalReader
类中,有一个方法CreateObjectUsingCreatorWithParameters
,它使用非默认构造函数处理对象的实例化。我已经复制了下面的相关位。
ResolvePropertyAndCreatorValues
方法从JSON中获取数据值,然后循环尝试将它们与构造函数参数匹配。与 1 不匹配的那些被添加到remainingPropertyValues
字典中。然后使用匹配的参数对对象进行实例化,使用null / default值填充任何间隙。稍后在该方法中的第二个循环(此处未示出)然后尝试在该对象上调用该字典中的剩余属性的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
实用程序方法。
反序列化的操作顺序/规则是否记录在某处?
据我所知。官方文档是here,但它没有详细说明。