https://dotnetfiddle.net/ka6XVw - 摆弄示例类型结构
假设我有一个实现IDictionary<string, T>
的类。 Json.Net 可以开箱即用地反序列化此类类型,创建该类型的实例并使用其索引器填充字典。问题是这个类还从它的基类继承了一个标有JsonProperty
属性的字符串Error
属性,我希望每当输入 json 包含error
字段时填充此属性。但是,在反序列化IDictionary
Json.Net 时,将所有字段视为字典条目,并尝试将带有 error
键的值添加到字典中。
将 json 反序列化为字典并将error
字段反序列化为 Error
属性的最简单、最干净的方法是什么?请注意,该类是泛型的,因此JsonExtensionData
不是一个选项(不将其值转换为提供的类型(。
示例有效字典 json:{ 'foo': '1', 'bar': '2' }
示例错误 json { 'error': 'blah' }
我从这个问题中得出了一个转换器解决方案。基本上,您将转换器附加到DictionaryResponse
类,并自己解释传入的 JSON。我懒得用JObject
解析:
class DictionaryResponseConverter : JsonConverter<ResponseBase>
{
public override ResponseBase ReadJson(
JsonReader reader, Type objectType,
ResponseBase existingValue, bool hasExistingValue,
JsonSerializer serializer)
{
// find the correct T and call the internal function through reflection
// as DictionaryResponse<T> is sealed, we don't care about inheritance
return (ResponseBase)GetType()
.GetMethod(nameof(InternalReadJson),
BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(objectType.GetGenericArguments()[0])
.Invoke(this, new object[]
{
reader,
existingValue,
hasExistingValue,
serializer
});
}
DictionaryResponse<T> InternalReadJson<T>(
JsonReader reader,
DictionaryResponse<T> existingValue, bool hasExistingValue,
JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var obj = JObject.Load(reader);
var error = (string)obj["error"];
bool hadError = obj.Remove("error");
//var result = new DictionaryResponse<T>();
var result = hasExistingValue ? existingValue : new DictionaryResponse<T>();
foreach (var kvp in obj)
result[kvp.Key] = kvp.Value.ToObject<T>();
if (hadError)
result.Error = error;
return result;
}
public override void WriteJson(
JsonWriter writer, ResponseBase value, JsonSerializer serializer)
{
// don't care about serialization
throw new NotImplementedException();
}
}
[JsonConverter(typeof(DictionaryResponseConverter))]
internal sealed class DictionaryResponse<T> : ResponseBase, IDictionary<string, T>
{
...