คุณต้องการทำให้โมเดลของคุณเป็นอนุกรมเป็นอาร์เรย์ของออบเจ็กต์ที่มีชื่อคุณสมบัติและค่าคุณสมบัติ โดยที่ชื่อและค่ามาจากการทำให้เป็นอนุกรม JSON เริ่มต้นสำหรับโมเดลของคุณ คุณสามารถทำได้ด้วย ทั่วไปที่กำหนดเอง JsonConverter<T>
ที่แปลระหว่างค่าเริ่มต้น การทำให้เป็นอนุกรมและการทำให้เป็นอนุกรมของอาร์เรย์
ตามค่าเริ่มต้น โมเดล UserPtr
ของคุณควรเป็นแบบอนุกรมดังนี้:
{
"my_var1": 1,
"my_var2": 2,
"my_var3": 2,
"my_var4": 4
}
แต่คุณได้รับอาร์เรย์ของออบเจ็กต์ที่มีคู่ชื่อ/ค่าเดียวดังที่แสดงในคำถามของคุณ โดยที่ชื่อนั้นสอดคล้องกับชื่อคุณสมบัติของโมเดลของคุณ คุณต้องการเชื่อมโยงอาร์เรย์นี้กับโมเดลของคุณ เพื่อให้บรรลุเป้าหมายนี้ คุณสามารถสร้างตัวแปลงทั่วไปที่คล้ายกับตัวแปลงจาก ยกเลิกการซีเรียลไลซ์ JSON จากผลการค้นหา Sharepoint 2013 ลงในรายการ MyClass ดังต่อไปนี้:
public class NamePtrPropertyArrayConverter<T> : JsonConverter<T> where T : class, new()
{
struct NamePtrDTO
{
public string name;
public object ptr;
}
public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
{
var obj = (JObject)JsonExtensions.DefaultFromObject(serializer, value);
serializer.Serialize(writer, obj.Properties().Select(p => new NamePtrDTO { name = p.Name, ptr = p.Value }));
}
public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
return null;
var array = serializer.Deserialize<List<NamePtrDTO>>(reader);
var obj = new JObject(array.Select(i => new JProperty(i.name, i.ptr)));
existingValue = existingValue ?? (T)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
using (var subReader = obj.CreateReader())
serializer.Populate(subReader, existingValue);
return existingValue;
}
}
public static partial class JsonExtensions
{
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
// DefaultFromObject() taken from this answer https://stackoverflow.com/a/29720068/3744182
// By https://stackoverflow.com/users/3744182/dbc
// To https://stackoverflow.com/questions/29719509/json-net-throws-stackoverflowexception-when-using-jsonconvert
public static JToken DefaultFromObject(this JsonSerializer serializer, object value)
{
if (value == null)
return JValue.CreateNull();
var dto = Activator.CreateInstance(typeof(DefaultSerializationDTO<>).MakeGenericType(value.GetType()), value);
var root = JObject.FromObject(dto, serializer);
return root["Value"].RemoveFromLowestPossibleParent() ?? JValue.CreateNull();
}
public static JToken RemoveFromLowestPossibleParent(this JToken node)
{
if (node == null)
return null;
// If the parent is a JProperty, remove that instead of the token itself.
var contained = node.Parent is JProperty ? node.Parent : node;
contained.Remove();
// Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
if (contained is JProperty)
((JProperty)node.Parent).Value = null;
return node;
}
interface IHasValue
{
object GetValue();
}
[JsonObject(NamingStrategyType = typeof(DefaultNamingStrategy), IsReference = false)]
class DefaultSerializationDTO<T> : IHasValue
{
public DefaultSerializationDTO(T value) => this.Value = value;
public DefaultSerializationDTO() { }
[JsonConverter(typeof(NoConverter)), JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Serialize)]
public T Value { get; set; }
object IHasValue.GetValue() => Value;
}
}
public class NoConverter : JsonConverter
{
// NoConverter taken from this answer https://stackoverflow.com/a/39739105/3744182
// By https://stackoverflow.com/users/3744182/dbc
// To https://stackoverflow.com/questions/39738714/selectively-use-default-json-converter
public override bool CanConvert(Type objectType) { throw new NotImplementedException(); /* This converter should only be applied via attributes */ }
public override bool CanRead => false;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}
จากนั้น ให้ทำการดีซีเรียลไลซ์โดยการเพิ่มตัวแปลงลงใน JsonSerializerSettings.Converters
:
var settings = new JsonSerializerSettings
{
Converters = { new NamePtrPropertyArrayConverter<UserPtr>() },
};
var model = JsonConvert.DeserializeObject<UserPtr>(strJson, settings);
หรือใช้ตัวแปลงโดยตรงกับโมเดลของคุณดังนี้:
[JsonConverter(typeof(NamePtrPropertyArrayConverter<UserPtr>))]
public class UserPtr
{
// Contents unchanged
}
สาธิตซอที่นี่
person
dbc
schedule
03.03.2021
"Value_my_var1"
เป็นจำนวนเต็มได้ ฉันขอสรุปได้ไหมว่าสิ่งเหล่านี้เป็นค่าจำนวนเต็มที่มีรูปแบบที่ถูกต้องซึ่งคุณแทนที่เมื่อพิมพ์คำถามของคุณ - person dbc   schedule 04.03.2021ptr
ที่แท้จริงของวัตถุmy_varX
เป็นจำนวนเต็มที่ถูกต้องทั้งหมด และแก้ไขคำถามของคุณเพื่อสะท้อนถึงสิ่งนั้น หากการแก้ไขของฉันไม่ถูกต้อง โปรดแก้ไขคำถามของคุณอีกครั้งเพื่อรวมตัวอย่างที่ทำซ้ำได้น้อยที่สุด - person dbc   schedule 04.03.2021