[英]Json.Net Deserialization Constructor vs. Property Rules
我正在使用 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 永遠不會被調用。
我最好的猜測是,反序列化器會跟蹤哪些屬性可以通過構造函數設置(按照某種約定,因為似乎忽略了大小寫),然后在可能的情況下使用屬性設置器來填補空白。
這是它的工作方式嗎? 反序列化的操作順序/規則是否記錄在某處?
我最好的猜測是,反序列化器會跟蹤哪些屬性可以通過構造函數設置(按照某種約定,因為似乎忽略了大小寫),然后在可能的情況下使用屬性設置器來填補空白。 這是它的工作方式嗎?
是的,這就是要點。 如果你看一下源代碼,你可以親眼看到。 在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
實用程序方法。
反序列化的操作順序/規則是否記錄在某處?
據我所知不是。 官方文檔在這里,但它沒有進入這個級別的細節。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.