我想序列化枚举类型,以便它返回一个数组,其中枚举作为一个对象,包含"值"," name"和数据注释值。我需要序列化方面的帮助。这是我到目前为止所做的事情: 枚举:
public enum Status
{
[Display(Name="Active status")]
Active = 1,
[Display(Name = "Deactive status")]
Deactive = 2,
[Display(Name = "Pending status")]
Pending = 3
}
应序列化的DTO对象:
public class ProjectDto
{
public Type StatusEnum { get; set; }
public Status CurrentStatus { get; set; }
}
分配值:
var project = new ProjectDto
{
CurrentStatus = Status.Active,
StatusEnum = typeof (Status)
};
var output = JsonConvert.SerializeObject(project);
要从枚举中获取值,我使用:
Enum.GetNames(typeof(Status)) //To get the names in the enum
Enum.GetValues(typeof(Status)) //To get the values in the enum
要获取数据注释名称值有点棘手,但我在本文中找到了帮助:http://geeksharp.com/2011/11/02/power-up-your-enumerations/ 他们创建了一个辅助方法,它将使用以下方法获取数据注释中的值:
public static string GetAttributeValue<T>(this Enum e,
Func<T, object> selector) where T : Attribute
{
var output = e.ToString();
var member = e.GetType().GetMember(output).First();
var attributes = member.GetCustomAttributes(typeof(T), false);
if (attributes.Length > 0)
{
var firstAttr = (T)attributes[0];
var str = selector(firstAttr).ToString();
output = string.IsNullOrWhiteSpace(str) ? output : str;
}
return output;
}
您可以使用以下方式获取值:
.GetAttributeValue<DisplayAttribute>(y => y.Name)
输出应该类似
{
statusEnum: [
{ "value": "1", "name": "Active", "label": "Active status" },
{ "value": "2", "name": "Deactive", "label": "Deactive status" },
{ "value": "3", "name": "Pending", "label": "Pending status" }
],
currentStatus: { "value": "1", "name": "Active", "label": "Active status" }
}
如上所述,我需要帮助创建自定义Json.NET序列化和反序列化以获得所需的输出。任何帮助都会受到影响。
答案 0 :(得分:7)
好的,这可能会被清理一下,但我会写两个自定义转换器:一个用于Enum
类型,另一个用于枚举值:
我创建了一个自定义类来序列化为您想要的最终结果:
public class EnumValue
{
public int Value { get; set; }
public string Name { get; set; }
public string Label { get; set; }
}
除了一个静态类,它用于从Enum
和枚举值中创建该类型的实例的一些工作:
public static class EnumHelpers
{
public static EnumValue GetEnumValue(object value, Type enumType)
{
MemberInfo member = enumType.GetMember(value.ToString())[0];
DisplayAttribute attribute =
member.GetCustomAttribute<DisplayAttribute>();
return new EnumValue
{
Value = (int)value,
Name = Enum.GetName(enumType, value),
Label = attribute.Name
};
}
public static EnumValue[] GetEnumValues(Type enumType)
{
Array values = Enum.GetValues(enumType);
EnumValue[] result = new EnumValue[values.Length];
for (int i = 0; i < values.Length; i++)
{
result[i] = GetEnumValue(
values.GetValue(i),
enumType);
}
return result;
}
}
然后有两个转换器类。第一个将System.Type
序列化为您想要的对象:
public class EnumTypeConverter : JsonConverter
{
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
EnumValue[] values = EnumHelpers.GetEnumValues((Type)value);
serializer.Serialize(writer, values);
}
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override bool CanRead { get { return false; } }
public override bool CanConvert(Type objectType)
{
return typeof(Type).IsAssignableFrom(objectType);
}
}
然后有一个序列化实际枚举值的那个:
public class EnumValueConverter : JsonConverter
{
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
EnumValue result = EnumHelpers.GetEnumValue(value, value.GetType());
serializer.Serialize(writer, result);
}
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override bool CanRead { get { return false; } }
public override bool CanConvert(Type objectType)
{
return objectType.IsEnum;
}
}
以下是您将如何使用它的全部内容:
var pr = new ProjectDto();
pr.CurrentStatus = Status.Active;
pr.StatusEnum = typeof(Status);
var settings = new JsonSerializerSettings();
settings.Converters = new JsonConverter[]
{
new EnumTypeConverter(),
new EnumValueConverter()
};
settings.Formatting = Newtonsoft.Json.Formatting.Indented;
string serialized = JsonConvert.SerializeObject(pr, settings);
答案 1 :(得分:1)
这是我遇到相同问题时经常采用的方法。 (Here's a fiddle,如果您想直接跳到一个可行的示例)
我经常发现自己需要枚举的其他值。因此,我喜欢创建一个属性来存储这些替代值。例如:
[AttributeUsage(AttributeTargets.Field)]
public class AlternativeValueAttribute : Attribute
{
public string JsonValue { get; set; }
public string DbValue { get; set; }
// and any other kind of alternative value you need...
}
(请注意,DbValue
属性与本演示目的无关...只是为了演示保留多个替代值。)
在构建枚举对象的时候,我在每个需要替代值的值上使用此属性。例如:
public enum ObjectState
{
[AlternativeValue(DbValue = "-1", JsonValue="is-unknown")]
Unknown,
[AlternativeValue(DbValue = "1", JsonValue="is-active")]
Active,
[AlternativeValue(DbValue = "0", JsonValue="is-inactive")]
Inactive
// ...
}
现在,我们需要创建一个转换器才能使用替代值。在这种情况下,我们要对Json进行序列化/反序列化,因此我们将创建一个JsonConverter
:
public class AlternativeValueJsonConverter<TEnum> : JsonConverter where TEnum : struct, IConvertible, IComparable, IFormattable
{
public override bool CanConvert( Type objectType )
{
// we can only convert if the type of object matches the generic type specified
return objectType == typeof( TEnum );
}
public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
{
if( objectType == typeof(TEnum) )
{
// cycle through the enum values
foreach(var item in (TEnum[])Enum.GetValues( typeof( TEnum ) ) )
{
// get the AlternativeValueAttribute, if it exists
var attr = item.GetType().GetTypeInfo().GetRuntimeField( item.ToString() )
.GetCustomAttribute<AlternativeValueAttribute>();
// if the JsonValue property matches the incoming value,
// return this enum value
if (attr != null && attr.JsonValue == reader.Value.ToString())
{
return item;
}
}
}
return null;
}
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
{
if( value.GetType() == typeof( TEnum ) )
{
// cycle through the enum values
foreach( var item in (TEnum[])Enum.GetValues( typeof( TEnum ) ) )
{
// if we've found the right enum value
if (item.ToString() == value.ToString() )
{
// get the attribute from the enum value
var attr = item.GetType().GetTypeInfo().GetRuntimeField( item.ToString() )
.GetCustomAttribute<AlternativeValueAttribute>();
if( attr != null)
{
// write out the JsonValue property's value
serializer.Serialize( writer, attr.JsonValue );
}
}
}
}
}
}
最后,要使用此JsonConverter
,我们需要用它来装饰枚举对象。因此,我们已经声明的ObjectState
枚举应该更新为使用转换器。例如:
[JsonConverter(typeof(AlternativeValueJsonConverter<ObjectState>))]
public enum ObjectState
{
[AlternativeValue(DbValue = "-1", JsonValue="is-unknown")]
Unknown,
[AlternativeValue(DbValue = "1", JsonValue="is-active")]
Active,
[AlternativeValue(DbValue = "0", JsonValue="is-inactive")]
Inactive
// ...
}
现在,出于演示目的,我们将创建一个包含ObjectState
枚举的简单POCO,并将其转换为Json以确保获得预期的结果:
public class DemoPoco
{
public ObjectState MyObjectState { get; set; }
}
public static void Main( string[] args )
{
DemoPoco demo = new DemoPoco { MyObjectState = ObjectState.Active };
var json = JsonConvert.SerializeObject( demo );
Console.WriteLine(json); // output: {"MyObjectState":"is-active"}
}