将字典键从 json 反序列化为 .net 中的枚举
Deserializing a dictionary key from json to an enum in .net
我正在阅读来自 API 的 json 回复,其中包含有关图像的信息。
它采用字典格式,如下所示:
images: {
low_resolution: {
url: "...",
width: 150,
height: 150
},
high_resolution: {
url: "...",
width: 450,
height: 450
}
}
我正在将响应反序列化为对象,并将图像反序列化为字典 属性,如下所示:
[DataContract()]
public class Post
{
...
[DataMember(Name = "images")]
public IDictionary<string, Media> Images { get; set; }
...
}
HttpResponseMessage response = await client.GetAsync(query);
if (response.IsSuccessStatusCode)
{
post = await response.Content.ReadAsAsync<Post>();
}
到目前为止一切正常,但我宁愿将图像分辨率信息反序列化为枚举值。
所以我创建了一个枚举 ImageResolution
并将字典键从 string
更改为 ImageResolution
.
这也反序列化成功,只要实际枚举值等于json字符串,但我想更改枚举值。
根据其他各种帖子,我尝试了以下方法:
[DataContract()]
public enum ImageResolution
{
[EnumMember(Value = "low_resolution")]
Low,
[EnumMember(Value = "high_resolution")]
High,
}
另外通过搜索我也尝试添加:
[JsonConverter(typeof(StringEnumConverter))]
但到目前为止没有任何效果。
响应中还有另一个 属性,我成功反序列化为枚举并使用 JsonConverter
属性更改枚举值,但这是一个直接的 属性 而不是字典键,所以我猜它是一个字典键导致了一些问题。
是否可以将 json 值反序列化为不同文本值的枚举字典键?
您需要按照指示为整个词典编写 CustomConverter here。
我修改了代码以使用 EnumMember 而不是另一个 post 中使用的前缀:
public class DictionaryWithSpecialEnumKeyConverter : JsonConverter
{
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var valueType = objectType.GetGenericArguments()[1];
var intermediateDictionaryType = typeof(Dictionary<,>).MakeGenericType(typeof(string), valueType);
var intermediateDictionary = (IDictionary)Activator.CreateInstance(intermediateDictionaryType);
serializer.Populate(reader, intermediateDictionary);
var finalDictionary = (IDictionary)Activator.CreateInstance(objectType);
foreach (DictionaryEntry pair in intermediateDictionary)
finalDictionary.Add(ToEnum<ImageResolution>(pair.Key.ToString()), pair.Value);
return finalDictionary;
}
private T ToEnum<T>(string str)
{
var enumType = typeof(T);
foreach (var name in Enum.GetNames(enumType))
{
var enumMemberAttribute = ((EnumMemberAttribute[])enumType.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true)).Single();
if (enumMemberAttribute.Value == str) return (T)Enum.Parse(enumType, name);
}
return default(T);
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
并在词典中使用它:
[DataContract]
public class Post
{
[JsonConverter(typeof(DictionaryWithSpecialEnumKeyConverter))]
[DataMember(Name = "images")]
public Dictionary<ImageResolution, Media> Images { get; set; }
}
我正在阅读来自 API 的 json 回复,其中包含有关图像的信息。
它采用字典格式,如下所示:
images: {
low_resolution: {
url: "...",
width: 150,
height: 150
},
high_resolution: {
url: "...",
width: 450,
height: 450
}
}
我正在将响应反序列化为对象,并将图像反序列化为字典 属性,如下所示:
[DataContract()]
public class Post
{
...
[DataMember(Name = "images")]
public IDictionary<string, Media> Images { get; set; }
...
}
HttpResponseMessage response = await client.GetAsync(query);
if (response.IsSuccessStatusCode)
{
post = await response.Content.ReadAsAsync<Post>();
}
到目前为止一切正常,但我宁愿将图像分辨率信息反序列化为枚举值。
所以我创建了一个枚举 ImageResolution
并将字典键从 string
更改为 ImageResolution
.
这也反序列化成功,只要实际枚举值等于json字符串,但我想更改枚举值。
根据其他各种帖子,我尝试了以下方法:
[DataContract()]
public enum ImageResolution
{
[EnumMember(Value = "low_resolution")]
Low,
[EnumMember(Value = "high_resolution")]
High,
}
另外通过搜索我也尝试添加:
[JsonConverter(typeof(StringEnumConverter))]
但到目前为止没有任何效果。
响应中还有另一个 属性,我成功反序列化为枚举并使用 JsonConverter
属性更改枚举值,但这是一个直接的 属性 而不是字典键,所以我猜它是一个字典键导致了一些问题。
是否可以将 json 值反序列化为不同文本值的枚举字典键?
您需要按照指示为整个词典编写 CustomConverter here。
我修改了代码以使用 EnumMember 而不是另一个 post 中使用的前缀:
public class DictionaryWithSpecialEnumKeyConverter : JsonConverter
{
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var valueType = objectType.GetGenericArguments()[1];
var intermediateDictionaryType = typeof(Dictionary<,>).MakeGenericType(typeof(string), valueType);
var intermediateDictionary = (IDictionary)Activator.CreateInstance(intermediateDictionaryType);
serializer.Populate(reader, intermediateDictionary);
var finalDictionary = (IDictionary)Activator.CreateInstance(objectType);
foreach (DictionaryEntry pair in intermediateDictionary)
finalDictionary.Add(ToEnum<ImageResolution>(pair.Key.ToString()), pair.Value);
return finalDictionary;
}
private T ToEnum<T>(string str)
{
var enumType = typeof(T);
foreach (var name in Enum.GetNames(enumType))
{
var enumMemberAttribute = ((EnumMemberAttribute[])enumType.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true)).Single();
if (enumMemberAttribute.Value == str) return (T)Enum.Parse(enumType, name);
}
return default(T);
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
并在词典中使用它:
[DataContract]
public class Post
{
[JsonConverter(typeof(DictionaryWithSpecialEnumKeyConverter))]
[DataMember(Name = "images")]
public Dictionary<ImageResolution, Media> Images { get; set; }
}