Người định cư riêng trong Json.Net


93

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.


1
Tôi đang tìm kiếm này hay rằng câu trả lời.
— marbel82

Câu trả lời:


112

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; }

Giải pháp thay thế

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ì:

  • Nó không yêu cầu bạn trang trí các thuộc tính của mình bằng các thuộc tính.
  • Nó hoạt động với cả hai { get; private set; }và chỉ { get; }.

19
Chỉ cần một lưu ý nhỏ: nó làm việc với {get;private set;}, không phải với{get;}
— tymtam

8
Chỉ cần một chút cập nhật. Bây giờ nó cũng hoạt động với {get;};
— Hav

1
@Hav Nó là phiên bản nào kể từ đó? Tôi vừa thử nghiệm v11.0.2 và nó không hoạt động {get;}
— tymtam

1
@tymtam Tôi nghĩ rằng nó chỉ hoạt động { get; }nếu kiểu có hàm tạo với tham số khớp với tên thuộc tính.
— Saeb Amini

2
@tymtam đã cập nhật câu trả lời với thay thế này và một ví dụ.
— Saeb Amini

77

Cập nhật, câu trả lời mới

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:

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamesContractResolver

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âu trả lời cũ (vẫn còn hiệu lực)

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/


2
Liên kết đến bài viết của bạn daniel.wertheim.se/2010/11/06/json-net-private-setters
— Jafin


1
Có vẻ như Alt 2 chắc chắn là cách để đi hiện nay. DefaultMembersSearchFlagsđã không được dùng nữa .
— Todd Menier

4
Với c # 6, {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.
— emragins

Có vẻ như Install-Package JsonNet.ContractResolvers sẽ được sử dụng ngay bây giờ. github.com/danielwertheim/jsonnet-contractresolvers
— Căn chỉnh

14

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()
};
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 cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.