2017-01-26 26 views
6

Tôi đang cố gắng để hiểu làm thế nào JsonConvert.DeserializeObject<X>(someJsonString) có thể thiết lập các giá trị bằng cách sử dụng các nhà xây dựng.Làm thế nào để JSON deserialization trong C# làm việc

using Newtonsoft.json 

public class X { 

    [JsonProperty("some_Property")] 
    public string SomeProperty {get;} 

    [JsonProperty("some_Property_2")] 
    public string SomeProperty2 {get;} 

    public X(string someProperty, string someProperty2) { 
     SomeProperty = someProperty; 
     SomeProperty2 = someProperty2; 
    } 

    public static X parseObject(string parseThisJson) { 
     JsonConvert.DeserializeObject<X>(someJsonString); 
    } 
} 

Ở trên mã tôi muốn hiểu cách JsonConvert.DeserializeObject có thể deserialize nó một cách chính xác. Việc tuần tự hóa json có sử dụng hàm tạo public X(string someProperty, string someProperty2) này không? Nếu như vậy constructor này được gọi và được sử dụng như thế nào?

Điều gì sẽ xảy ra là parseThisJson có nhiều cặp khóa giá trị hơn ngoài some_Property và some_Property_2?

+2

bạn có thể kiểm tra trong 1 phút. Đặt breakpoint trong constructor –

+0

Không hoàn toàn, điều này phụ thuộc vào loại serialization/deserialization thực tế. XmlSerialization ví dụ * * sử dụng hàm tạo mặc định. Tuy nhiên điều này là vô nghĩa đối với câu hỏi thực tế ở đây. – HimBromBeere

+3

Bạn biết rằng đó là mã nguồn mở và bạn có thể kiểm tra nó trên github phải không? –

Trả lời

7

Sau khi đào sâu vào các nguồn Newtonsoft.Json Tôi có thể cho bạn biết thuật toán của việc khởi tạo đối tượng được sử dụng ở đó. Và có, hàm tạo là gần như luôn được gọi (*). Câu hỏi chỉ là "cái nào?" Đây là phiên bản đầy màu sắc của câu trả lời:

picking constructor

TL; DR Trước hết, Newtonsoft.Json tạo JsonContract của các loại mà bạn đang đi để deserialize. Đó là lớp trừu tượng. Và nó có triển khai khác nhau cho từ điển, mảng, đối tượng, vv Trong trường hợp của bạn JsonObjectContract sẽ được tạo. Hợp đồng chứa nhiều siêu dữ liệu khác nhau về loại deserialized. thú vị nhất đối với chúng tôi là:

  • IsInstantiable - xác định liệu loại deserialized là instantiable (xem dưới đây)
  • Properties - đó là tập hợp các thuộc tính đối tượng
  • DefaultCreator - Phương pháp tạo mặc định dùng để tạo ra đối tượng Func<object>
  • DefaultCreatorNonPublic - xác định xem hàm tạo mặc định có công khai không
  • OverrideCreator - trình tạo không mặc định, được sử dụng nếu JsonConstructorAttribute là applie d phản đối của constructor
  • ParametrizedCreator - tác giả trong đó kêu gọi constructor paramterized, nó được sử dụng nếu chúng ta không có không phải người sáng tạo mặc định cũng không ghi đè
  • CreatorParameters - bộ sưu tập các thuộc tính được sử dụng cho tác giả ghi đè hoặc tạo parametrized
  • MemberSerialization - giá trị này xác định cách thức các thuộc tính và các trường được tuần tự hóa. Theo mặc định, nó được đặt thành OptOut - tức là tất cả các thành viên công khai đều được đăng. Nếu bạn muốn loại trừ một số, bạn nên sử dụng thuộc tính JsonIgnore. Nhưng cũng có tùy chọn Fields, cho biết tất cả các trường công khai và riêng tư sẽ được tuần tự hóa. Có một số để bật tùy chọn này. Nhưng theo mặc định, nó bị vô hiệu hóa.

Một số siêu dữ liệu này có thể được truy xuất bằng cách phản ánh metdata loại. Ví dụ. IsInstantiable được tính toán bằng cách kiểm tra xem loại deserialized không phải là trừu tượng và không phải là giao diện. Một số siêu dữ liệu được thêm bởi DefaultContractResolver. Đặc biệt, nó định nghĩa cách thức đối tượng nên được xây dựng. Trong mã giả:

if (contract.IsInstantiable) 
{ 
    if (type has default constructor or its a value type) 
    { 
     contract.DefaultCreator = get default (parameterless) constructor; 
     contract.DefaultCreatorNonPublic = check if default constructor public 
    } 

    if (we have constructor marked with JsonConstructorAttribute) 
    { 
     contract.OverrideCreator = constructor marked with attribute 
     contract.CreatorParameters = get properties which match constructor parameters 
    } 
    else if (contract.MemberSerialization == MemberSerialization.Fields) 
    { 
     // only if the upplication if fully trusted 
     contract.DefaultCreator = FormatterServices.GetUninitializedObject 
    } 
    else if (contract.DefaultCreator == null || contract.DefaultCreatorNonPublic) 
    { 
     if (we have one public constructor with parameters) 
     { 
       contract.ParametrizedCreator = constructor with parameters; 
       contract.CreatorParameters = get properties which match ctor parameters 
     } 
    } 
} 

Vì vậy, bạn có thể thấy prioirty đến hàm tạo được đánh dấu bằng thuộc tính JsonConstructorAttribute. Bạn cũng sẽ gặp lỗi nếu có nhiều hơn một hàm tạo như vậy.

(*) Tiếp theo là trường hợp duy nhất khi đối tượng có thể được tạo mà không cần gọi hàm tạo. Ví dụ. nếu bạn sẽ đánh dấu lớp học với thuộc tính [JsonObject(MemberSerialization = MemberSerialization.Fields)] để tuần tự hóa các trường riêng tư.

Sau đó, chúng tôi kiểm tra xem chúng tôi có hàm tạo tham số mặc định không phải là riêng tư hay không. Nếu vậy, thì chúng ta đi tìm một hàm tạo khác - một hàm có tham số và phải được công khai. Nếu có nhiều hơn một hàm tạo như vậy, bạn cũng sẽ gặp lỗi.

Và điều cuối cùng cần lưu ý - CraeatorParameters. Newtonsoft.Json sử dụng sự phản chiếu để lấy các tham số của hàm tạo và sau đó cố gắng tìm đối sánh gần nhất theo tên của các tham số hàm dựng này cho các thuộc tính của đối tượng. Nó cũng kiểm tra loại thuộc tính và thông số để khớp. Nếu không tìm thấy kết quả phù hợp, thì giá trị mặc định sẽ được chuyển tới hàm tạo tham số này.

+1

Cảm ơn bạn đã giải thích tuyệt vời. Tôi có một câu hỏi, bạn đã nói _Newtonsoft.Json sử dụng sự phản chiếu để nhận các tham số của hàm tạo và sau đó cố gắng tìm đối sánh gần nhất theo tên của các tham số hàm dựng này cho thuộc tính của đối tượng_ trong ý nghĩa này của đối tượng _closest bằng name_ có tên thuộc tính don ' t cần phải là một trận đấu 100%? ví dụ SomeProprty sẽ được coi là phù hợp với SomeProperty? – user2358262

+0

@ user2358262 trước tiên nó cố gắng lấy thuộc tính có tên phù hợp 100%, nhưng nếu nó không thành công, thì nó sẽ cố gắng tìm trường hợp bỏ qua thuộc tính tên. Tôi tin rằng điều đó được thực hiện do quy ước đặt tên khác nhau. Đối với các thuộc tính, chúng tôi sử dụng đặt tên PascalCase và tham số camelCase. Bạn có thể kiểm tra mã này [tại đây] (https://github.com/JamesNK/Newtonsoft.Json/blob/cf6a917a46b532558578c53d34cdc4f39ec0560a/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs) –

Các vấn đề liên quan