Json.net serialize / deserialize các kiểu dẫn xuất?


98

json.net (newtonsoft)
Tôi đang xem qua tài liệu nhưng không thể tìm thấy gì về điều này hoặc cách tốt nhất để làm điều đó.

public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

JsonConvert.Deserialize<List<Base>>(text);

Bây giờ tôi có các đối tượng Nguồn gốc trong danh sách được tuần tự hóa. Làm cách nào để giải mã hóa danh sách và lấy lại các loại dẫn xuất?


Đó không phải là cách kế thừa hoạt động. Bạn có thể chỉ định JsonConvert.Deserialize <Derived> (text); để bao gồm trường Tên. Vì Derived IS A Base (không phải ngược lại), Base không biết gì về định nghĩa của Derived.
M.Babcock

Xin lỗi, làm rõ một chút. Vấn đề là tôi có một danh sách chứa cả đối tượng cơ sở và đối tượng dẫn xuất. Vì vậy, tôi cần tìm ra cách tôi nói với newtonsoft cách giải mã hóa các mục dẫn xuất.
Sẽ

Tôi đã làm bạn giải quyết điều này. Tôi có cùng một vấn đề
Luis Carlos Chavarría

Câu trả lời:


46

Nếu bạn đang lưu trữ kiểu trong của bạn text(như bạn nên làm trong trường hợp này), bạn có thể sử dụng JsonSerializerSettings.

Xem: cách giải mã JSON thành IEnumerable <BaseType> với Newtonsoft JSON.NET

Hãy cẩn thận, mặc dù. Sử dụng bất kỳ thứ gì khác ngoài việc TypeNameHandling = TypeNameHandling.Nonecó thể mở ra lỗ hổng bảo mật .


24
Bạn cũng có thể sử dụng TypeNameHandling = TypeNameHandling.Auto- điều này sẽ chỉ thêm một thuộc $typetính cho các trường hợp mà kiểu được khai báo (tức là Base) không khớp với kiểu thể hiện (tức là Derived). Bằng cách này, nó không làm cồng kềnh JSON của bạn nhiều như vậy TypeNameHandling.All.
AJ Richardson

Tôi tiếp tục nhận được Lỗi giải quyết loại được chỉ định trong JSON '..., ...'. Đường dẫn '$ type', dòng 1, vị trí 82. Bạn có ý kiến ​​gì không?
briba

3
Hãy cẩn thận khi sử dụng này trên một thiết bị đầu cuối công cộng vì nó mở ra vấn đề an ninh: alphabot.com/security/blog/2017/net/...
gjvdkamp

1
@gjvdkamp JEEZ cảm ơn vì điều này, tôi không biết về điều này. Sẽ thêm vào bài viết của tôi.
kamranicus

96

Bạn phải bật Xử lý tên loại và chuyển nó đến bộ tuần tự (de) làm tham số cài đặt.

Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);

Điều này sẽ dẫn đến việc giải mã hóa chính xác các lớp dẫn xuất. Một hạn chế của nó là nó sẽ đặt tên cho tất cả các đối tượng bạn đang sử dụng, như vậy nó sẽ đặt tên cho danh sách bạn đang đưa các đối tượng vào.


31
+1. Tôi đã googling trong 30 phút cho đến khi tôi thực sự phát hiện ra rằng bạn cần sử dụng các cài đặt tương tự cho SerializeObject & DeserializeObject. Tôi đã giả định rằng nó sẽ sử dụng $ type một cách ngầm định nếu nó ở đó khi deserializing, tôi ngớ ngẩn.
Erti-Chris Eelmaa

24
TypeNameHandling.Autocũng sẽ làm điều đó và đẹp hơn vì nó không viết tên kiểu cá thể khi nó khớp với kiểu của trường / thuộc tính, điều này thường xảy ra đối với hầu hết các trường / thuộc tính.
Roman Starkov

2
Điều này không hoạt động khi quá trình giải mã hóa được thực hiện trên một giải pháp / dự án khác. Khi tuần tự hóa, tên của Giải pháp được nhúng bên trong dưới dạng: "SOLUTIONNAME.Models.Model". Khi deserialization trên giải pháp khác, nó sẽ ném "JsonSerializationException: Không thể tải lắp ráp 'SOLUTIONNAME'.
Sad CRUD Developer

19

Vì câu hỏi này rất phổ biến, có thể hữu ích nếu bạn thêm vào những việc cần làm nếu bạn muốn kiểm soát tên thuộc tính kiểu và giá trị của nó.

Cách lâu dài là viết các tùy chỉnh JsonConverterđể xử lý (de) tuần tự hóa bằng cách kiểm tra và thiết lập thuộc tính kiểu theo cách thủ công.

Một cách đơn giản hơn là sử dụng JsonSubTypes , xử lý tất cả bảng soạn sẵn thông qua các thuộc tính:

[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }
}

public class Dog : Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }
}

3
Tôi nhận được sự cần thiết, nhưng tôi không phải là một fan hâm mộ của việc phải làm cho lớp cơ sở nhận thức của tất cả các "KnownSubType" s ...
Matt Knowles

2
Có các tùy chọn khác nếu bạn xem tài liệu. Tôi chỉ cung cấp ví dụ mà tôi thích hơn.
rzippo

1
Đây là cách tiếp cận an toàn hơn mà không khiến dịch vụ của bạn tải các loại tùy ý khi hủy tuần tự hóa.
David Burg

3

Sử dụng JsonKnownTypes này , cách sử dụng rất giống, nó chỉ thêm dấu phân biệt vào json:

[JsonConverter(typeof(JsonKnownTypeConverter<BaseClass>))]
[JsonKnownType(typeof(Base), "base")]
[JsonKnownType(typeof(Derived), "derived")]
public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

Bây giờ khi bạn tuần tự hóa đối tượng trong json sẽ được thêm "$type"với "base""derived"giá trị và nó sẽ được sử dụng để giải mã

Ví dụ về danh sách được tuần tự hóa:

[
    {"Name":"some name", "$type":"base"},
    {"Name":"some name", "Something":"something", "$type":"derived"}
]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.