ฉันรู้ว่ามีแอตทริบิวต์ที่จะจัดการกับตัวตั้งค่าส่วนตัว แต่ฉันต้องการให้พฤติกรรมนี้เป็นค่าเริ่มต้นมีวิธีที่จะทำให้สำเร็จหรือไม่ ยกเว้นการปรับแต่งแหล่งที่มา จะดีมากถ้ามีการตั้งค่านี้
ฉันรู้ว่ามีแอตทริบิวต์ที่จะจัดการกับตัวตั้งค่าส่วนตัว แต่ฉันต้องการให้พฤติกรรมนี้เป็นค่าเริ่มต้นมีวิธีที่จะทำให้สำเร็จหรือไม่ ยกเว้นการปรับแต่งแหล่งที่มา จะดีมากถ้ามีการตั้งค่านี้
คำตอบ:
ฉันมาที่นี่เพื่อค้นหาแอตทริบิวต์จริงที่ทำให้ 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; }
{get;private set;}
ได้กับ{get;}
{ get; }
กรณีที่ประเภทมีตัวสร้างที่มีพารามิเตอร์ตรงกับชื่อคุณสมบัติ
ฉันได้เขียน NuGet การแจกจ่ายซอร์สสำหรับสิ่งนี้ซึ่งติดตั้งไฟล์เดียวที่มีตัวแก้ไขสัญญาที่กำหนดเองสองตัว:
ติดตั้ง 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/
{get; }
จะไม่เทียบเท่ากับ{ get; private set; }
. สำหรับวิธีแรกproperty.GetSetMethod(true)
ผลตอบแทนและหลังnull
true
สิ่งนี้ทำให้ฉันประหลาดใจ คุณต้องมีprivate set;
เพื่อให้ deserialization ทำงานได้ตามที่คาดไว้
คำตอบของ @ 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()
};