ตัวตั้งค่าส่วนตัวใน Json.Net


96

ฉันรู้ว่ามีแอตทริบิวต์ที่จะจัดการกับตัวตั้งค่าส่วนตัว แต่ฉันต้องการให้พฤติกรรมนี้เป็นค่าเริ่มต้นมีวิธีที่จะทำให้สำเร็จหรือไม่ ยกเว้นการปรับแต่งแหล่งที่มา จะดีมากถ้ามีการตั้งค่านี้


1
ฉันกำลังมองหาคำตอบนี้หรือนั่น
marbel82

คำตอบ:


116

ฉันมาที่นี่เพื่อค้นหาแอตทริบิวต์จริงที่ทำให้ Json.NET เติมคุณสมบัติแบบอ่านอย่างเดียวเมื่อ deserializing และนั่นก็เป็นเพียง[JsonProperty]:

[JsonProperty]
public Guid? ClientId { get; private set; }

โซลูชันทางเลือก

เพียงระบุตัวสร้างที่มีพารามิเตอร์ตรงกับคุณสมบัติของคุณ:

public class Foo
{
    public string Bar { get; }

    public Foo(string bar)
    {
        Bar = bar;
    }
}

ตอนนี้ใช้งานได้:

string json = "{ \"bar\": \"Stack Overflow\" }";

var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow

ฉันชอบแนวทางนี้มากที่สุดตั้งแต่:

  • ไม่จำเป็นต้องให้คุณตกแต่งคุณสมบัติของคุณด้วยแอตทริบิวต์
  • จะทำงานร่วมกับทั้งสองและเพียงแค่{ get; private set; }{ get; }

21
หมายเหตุเล็ก ๆ น้อย ๆ : ใช้งาน{get;private set;}ได้กับ{get;}
tymtam

8
อัปเดตเพียงเล็กน้อย ตอนนี้ยังใช้งานได้กับ {get;};
Hav

1
@Hav มันเป็นรุ่นอะไร? ฉันเพิ่งทดสอบ v11.0.2 และใช้งานไม่ได้ {get;}
tymtam

1
@tymtam ฉันคิดว่ามันใช้ได้เฉพาะใน{ get; }กรณีที่ประเภทมีตัวสร้างที่มีพารามิเตอร์ตรงกับชื่อคุณสมบัติ
แสบอามินี

2
@tymtam อัปเดตคำตอบพร้อมทางเลือกนี้และตัวอย่าง
แสบอามินี

78

อัปเดตคำตอบใหม่

ฉันได้เขียน NuGet การแจกจ่ายซอร์สสำหรับสิ่งนี้ซึ่งติดตั้งไฟล์เดียวที่มีตัวแก้ไขสัญญาที่กำหนดเองสองตัว:

  • PrivateSetterContractResolver
  • PrivateSetterCamelCasePropertyNamesContractResolver

ติดตั้ง NuGet:

Install-Package JsonNet.PrivateSettersContractResolvers.Source

จากนั้นใช้ตัวแก้ไขใด ๆ :

var settings = new JsonSerializerSettings
{
    ContractResolver = new PrivateSetterContractResolver()
};

var model = JsonConvert.DeserializeObject<Model>(json, settings);

คุณสามารถอ่านได้ที่นี่: http://danielwertheim.se/json-net-private-setters-nuget/

GitHub repo: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers

คำตอบเก่า (ยังใช้ได้)

มีสองทางเลือกที่สามารถแก้ปัญหาได้

Alt 1: บน deserializers

ContractResolver.DefaultMembersSearchFlags =
                             DefaultMembersSearchFlags | BindingFlags.NonPublic;

ตัวเลือกการทำให้เป็นอนุกรมเริ่มต้นรองรับสมาชิกคลาสทุกประเภท ดังนั้นโซลูชันนี้จะส่งคืนชนิดสมาชิกส่วนตัวทั้งหมดรวมทั้งฟิลด์ ฉันสนใจเพียงแค่สนับสนุนเซ็ตเตอร์ส่วนตัวเท่านั้น

Alt2: สร้าง ContractResolver ที่กำหนดเอง:

ดังนั้นนี่คือตัวเลือกที่ดีกว่าเนื่องจากเราเพิ่งตรวจสอบคุณสมบัติ

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

สำหรับข้อมูลเพิ่มเติมโปรดอ่านโพสต์ของฉัน: http://danielwertheim.se/json-net-private-setters/


2
ลิงก์ไปยังโพสต์ของคุณdaniel.wertheim.se/2010/11/06/json-net-private-setters
Jafin

1
@Jafin url ตายแล้วdanielwertheim.wordpress.com/2010/11/06/…มีแล้ว
Chris Marisic

1
ดูเหมือนว่าAlt 2จะเป็นหนทางที่จะไปในปัจจุบัน DefaultMembersSearchFlagsได้รับการเลิกใช้
Todd Menier

4
ด้วย c # 6 {get; }จะไม่เทียบเท่ากับ{ get; private set; }. สำหรับวิธีแรกproperty.GetSetMethod(true)ผลตอบแทนและหลังnull trueสิ่งนี้ทำให้ฉันประหลาดใจ คุณต้องมีprivate set;เพื่อให้ deserialization ทำงานได้ตามที่คาดไว้
emragins

ดูเหมือนว่าควรใช้ Install-Package JsonNet.ContractResolvers github.com/danielwertheim/jsonnet-contractresolvers
AlignedDev

14

คำตอบของ @ Daniel (Alt2) เป็นจุดที่ชัดเจน แต่ฉันต้องการสิ่งนี้เพื่อใช้งานได้กับทั้งตัวตั้งค่าส่วนตัวและตัวรับ (ฉันกำลังทำงานกับ API ที่มีสิ่งที่เขียนอย่างเดียวจริง ๆ เช่นuser.password) นี่คือสิ่งที่ฉันลงเอยด้วย:

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

จดทะเบียนด้วยประการฉะนี้:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
    ContractResolver = new NonPublicPropertiesResolver()
};
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.