簡體   English   中英

Json.Net 反序列化構造函數與屬性規則

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM