Tôi biết có một thuộc tính để xử lý các bộ cài đặt riêng tư nhưng tôi muốn hành vi này làm mặc định, có cách nào để thực hiện điều này không? Ngoại trừ việc tinh chỉnh nguồn. Sẽ thật tuyệt nếu có một thiết lập cho việc này.
Câu trả lời:
Tôi đến đây để tìm thuộc tính thực tế làm cho Json.NET điền thuộc tính chỉ đọc khi giải không khí và điều đó đơn giản [JsonProperty], ví dụ:
[JsonProperty]
public Guid? ClientId { get; private set; }
Chỉ cần cung cấp một hàm tạo có tham số phù hợp với thuộc tính của bạn:
public class Foo
{
public string Bar { get; }
public Foo(string bar)
{
Bar = bar;
}
}
Bây giờ nó hoạt động:
string json = "{ \"bar\": \"Stack Overflow\" }";
var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow
Tôi thích cách tiếp cận này hơn nếu có thể vì:
{ get; private set; }và chỉ { get; }.{get;private set;}, không phải với{get;}
{ get; }nếu kiểu có hàm tạo với tham số khớp với tên thuộc tính.
Tôi đã viết một bản phân phối nguồn NuGet cho việc này, cài đặt một tệp duy nhất với hai trình giải quyết hợp đồng tùy chỉnh:
Cài đặt NuGet:
Install-Package JsonNet.PrivateSettersContractResolvers.Source
Sau đó, chỉ cần sử dụng bất kỳ trình giải quyết nào:
var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};
var model = JsonConvert.DeserializeObject<Model>(json, settings);
Bạn có thể đọc về nó tại đây: http://danielwertheim.se/json-net-private-setters-nuget/
GitHub repo: https://github.com/danielwertheim/jsonnet-privateetterscontractresolvers
Có hai lựa chọn thay thế có thể giải quyết vấn đề.
Thay thế 1: Trên bộ khử không khí
ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;
Tùy chọn tuần tự hóa mặc định hỗ trợ tất cả các loại thành viên lớp. Do đó, giải pháp này sẽ trả về tất cả các loại thành viên riêng tư bao gồm các trường. Tôi chỉ quan tâm đến việc hỗ trợ các setters tư nhân.
Alt2: Tạo ContractResolver tùy chỉnh:
Do đó, đây là lựa chọn tốt hơn vì chúng tôi chỉ kiểm tra các thuộc tính.
public class SisoJsonDefaultContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{
//TODO: Maybe cache
var prop = base.CreateProperty(member, memberSerialization);
if (!prop.Writable)
{
var property = member as PropertyInfo;
if (property != null)
{
var hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
}
}
return prop;
}
}
Để biết thêm thông tin, hãy đọc bài đăng của tôi: http://danielwertheim.se/json-net-private-setters/
{get; }KHÔNG tương đương với { get; private set; }. Đối với cách đầu tiên property.GetSetMethod(true)trả về nullvà cách sau true. Điều này làm tôi ngạc nhiên. Bạn phải có private set;để deserialization hoạt động như mong đợi.
Câu trả lời của @ Daniel (Alt2) là đúng, nhưng tôi cần điều này để làm việc cho cả bộ cài đặt riêng và bộ nhận (tôi đang làm việc với một API thực sự có một số thứ chỉ ghi, chẳng hạn như user.password.) Đây là những gì tôi đã kết thúc:
public class NonPublicPropertiesResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
var prop = base.CreateProperty(member, memberSerialization);
if (member is PropertyInfo pi) {
prop.Readable = (pi.GetMethod != null);
prop.Writable = (pi.SetMethod != null);
}
return prop;
}
}
Đã đăng ký như vậy:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
ContractResolver = new NonPublicPropertiesResolver()
};