我想序列化一个枚举类型,以便它返回一个数组,其中枚举作为包含"值"、"名称"和数据注释值的对象。我需要序列化方面的帮助。这是我到目前为止所做的:枚举:
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 序列化和反序列化以获得所需的输出。任何帮助都将被征用。
好的,这可能可以清理一下,但我会编写两个自定义转换器:一个用于Enum
类型,另一个用于枚举值:
我创建了一个自定义类来序列化为您想要的最终结果:
public class EnumValue
{
public int Value { get; set; }
public string Name { get; set; }
public string Label { get; set; }
}
以及一个静态类,该类执行一些从 Enum
s 和枚举值创建该类型实例的工作:
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);
示例:https://dotnetfiddle.net/BVp7a2
这是我在面对相同问题时经常采取的方法。(这是一个小提琴,如果你想直接跳到一个工作示例(
设置枚举
我经常发现自己需要枚举的替代值。出于这个原因,我喜欢创建一个属性来存储这些替代值。例如:
[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"}
}