gpt4 book ai didi

c# - Json.NET - CustomCreationConverter 中单个属性的默认反序列化行为

转载 作者:可可西里 更新时间:2023-11-01 09:10:08 25 4
gpt4 key购买 nike

在以下场景中,当 CrazyItemConverter 遇到我要反序列化到的类型中存在的 JSON 属性时,如何让它照常运行?

我有一些像这样的 JSON:

{
"Item":{
"Name":"Apple",
"Id":null,
"Size":5,
"Quality":2
}
}

JSON 被反序列化为一个看起来很像这样的类:

[JsonConverter(typeof(CrazyItemConverter))]
public class Item
{
[JsonConverter(typeof(CrazyStringConverter))]
public string Name { get; set; }

public Guid? Id { get; set; }

[JsonIgnore]
public Dictionary<string, object> CustomFields
{
get
{
if (_customFields == null)
_customFields = new Dictionary<string, object>();
return _customFields;
}
}

...
}

CrazyItemConverter 填充已知属性的值并将未知属性放入 CustomFields。其中的ReadJson是这样的:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var outputObject = Create(objectType);
var objProps = objectType.GetProperties().Select(p => p.Name).ToArray();

while (reader.Read())
{
if (reader.TokenType == JsonToken.PropertyName)
{
string propertyName = reader.Value.ToString();
if (reader.Read())
{
if (objProps.Contains(propertyName))
{
// No idea :(
// serializer.Populate(reader, outputObject);
}
else
{
outputObject.AddProperty(propertyName, reader.Value);
}
}
}
}
return outputObject;
}

在反序列化期间,当 CrazyItemConverter 遇到已知属性时,我希望它像往常一样运行。意思是,尊重 [JsonConverter(typeof(CrazyStringConverter))] for Name

使用下面的代码来设置已知属性,但是它会在可空值上抛出异常并且不尊重我的其他 JsonConverter。

PropertyInfo pi = outputObject.GetType().GetProperty(readerValue, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var convertedValue = Convert.ChangeType(reader.Value, pi.PropertyType);
pi.SetValue(outputObject, convertedValue, null);

有什么想法吗?

更新:我了解到 serializer.Populate(reader, outputObject); 是反序列化整个事情的方法,但如果你这样做,它似乎不起作用需要逐个属性的默认功能。

最佳答案

如果我没理解错的话,您的 CrazyItemConverter 存在,这样您就可以将 JSON 中的已知属性反序列化为强类型属性,同时仍将 JSON 中可能存在的“额外”字段保留到词典。

事实证明,Json.Net 已经内置了这个功能(从 5.0 release 5 开始),所以你不需要疯狂的转换器。相反,您只需要使用 [JsonExtensionData] 属性标记您的字典。 (有关详细信息,请参阅 the author's blog。)

所以你的 Item 类看起来像这样:

public class Item
{
[JsonConverter(typeof(CrazyStringConverter))]
public string Name { get; set; }

public Guid? Id { get; set; }

[JsonExtensionData]
public Dictionary<string, object> CustomFields
{
get
{
if (_customFields == null)
_customFields = new Dictionary<string, object>();
return _customFields;
}
private set
{
_customFields = value;
}
}
private Dictionary<string, object> _customFields;
}

然后你可以像往常一样反序列化它。演示:

class Program
{
static void Main(string[] args)
{
string json = @"
{
""Item"":
{
""Name"":""Apple"",
""Id"":""4b7e9f9f-7a30-4f79-8e47-8b50ea26ddac"",
""Size"":5,
""Quality"":2
}
}";

Item item = JsonConvert.DeserializeObject<Wrapper>(json).Item;
Console.WriteLine("Name: " + item.Name);
Console.WriteLine("Id: " + item.Id);
foreach (KeyValuePair<string, object> kvp in item.CustomFields)
{
Console.WriteLine(kvp.Key + ": " + kvp.Value);
}
}
}

public class Wrapper
{
public Item Item { get; set; }
}

class CrazyStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
// Reverse the string just for fun
return new string(token.ToString().Reverse().ToArray());
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

输出:

Name: elppA
Id: 4b7e9f9f-7a30-4f79-8e47-8b50ea26ddac
Size: 5
Quality: 2

关于c# - Json.NET - CustomCreationConverter 中单个属性的默认反序列化行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21537940/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com