我有一个枚举:
public enum Action {
Remove=1,
Add=2
}
还有一堂课:
[DataContract]
public class Container {
[DataMember]
public Action Action {get; set;}
}
当将 Container 实例序列化为 json 时,我得到:
{Action:1}
(如果 Action 为“Remove”)。
我想得到:
{Action:Remove}
(我需要枚举的 ToString 形式而不是 int)
我可以在不向班级添加其他成员的情况下完成此操作吗?
您只需添加属性即可:
[Newtonsoft.Json.JsonConverter(typeof(StringEnumConverter))]
未序列化为字符串的枚举属性。
或者,如果您想要更奇特的格式,您可以使用下面的属性来告诉 JSON 序列化程序仅序列化您已根据需要格式化的属性。有点取决于您的其余实施。它也识别属性上的 DataMember 属性。
[JsonObject(MemberSerialization = MemberSerialization.OptOut)]
public class Container
{
public Action Action { get; set; }
[JsonProperty(PropertyName = "Action")]
public string ActionString
{
get
{
return Action.ToString();
}
}
}
Json.Net,您可以将自定义 StringEnumConverter
定义为
public class MyStringEnumConverter : Newtonsoft.Json.Converters.StringEnumConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is Action)
{
writer.WriteValue(Enum.GetName(typeof(Action),(Action)value));// or something else
return;
}
base.WriteJson(writer, value, serializer);
}
}
并序列化为
string json=JsonConvert.SerializeObject(container,new MyStringEnumConverter());
JsonConvert.SerializeObject(myObject, Formatting.Indented, new StringEnumConverter());
来自
MSDN:
解决此问题的唯一实用方法(允许最终用户指定字符串而不是数字)是不在合约中使用枚举。相反,实际的答案是将枚举替换为字符串并对值执行内部验证,以便可以将其解析为有效的枚举表示之一。枚举成员值在 JSON 中被视为数字,即 与数据合同中处理它们的方式不同,它们在数据合同中的处理方式不同 包含为成员名称。有关数据合同的更多信息 处理,请参阅数据契约中的枚举类型。
- 例如,如果您有
public enum Color {red, green, blue, yellow, pink}
,则序列化 Yellow 会生成数字 3 而不是字符串 “黄色”。- 所有枚举成员都是可序列化的。 EnumMemberAttribute 和 如果使用 NonSerializedAttribute 属性,则会被忽略。
- 可以反序列化一个不存在的枚举值 - 例如, 值 87 甚至可以反序列化为之前的 Color 枚举 虽然没有定义相应的颜色名称。
- 标志枚举并不特殊,其处理方式与任何其他枚举相同。
或者(尽管不是假装的),您可以将 JSON 格式化程序替换为您自己的格式化程序,这将像其他格式化程序一样尊重枚举。
EnumMemberAttribute
的值进行序列化。我看到的最大优点是:
string
而不是
int
[DataContract]
public class SerializableClass {
public Shapes Shape {get; set;} //Do not use the DataMemberAttribute in the public property
[DataMember(Name = "shape")]
private string ShapeSerialization // Notice the PRIVATE here!
{
get { return EnumHelper.Serialize(this.Shape); }
set { this.Shape = EnumHelper.Deserialize<Shapes>(value); }
}
}
EnumHelper.cs
/* Available at: https://gist.github.com/mniak/a4d09264ad1ca40c489178325b98935b */
public static class EnumHelper
{
public static string Serialize<TEnum>(TEnum value)
{
var fallback = Enum.GetName(typeof(TEnum), value);
var member = typeof(TEnum).GetMember(value.ToString()).FirstOrDefault();
if (member == null)
return fallback;
var enumMemberAttributes = member.GetCustomAttributes(typeof(EnumMemberAttribute), false).Cast<EnumMemberAttribute>().FirstOrDefault();
if (enumMemberAttributes == null)
return fallback;
return enumMemberAttributes.Value;
}
public static TEnum Deserialize<TEnum>(string value) where TEnum : struct
{
TEnum parsed;
if (Enum.TryParse<TEnum>(value, out parsed))
return parsed;
var found = typeof(TEnum).GetMembers()
.Select(x => new
{
Member = x,
Attribute = x.GetCustomAttributes(typeof(EnumMemberAttribute), false).OfType<EnumMemberAttribute>().FirstOrDefault()
})
.FirstOrDefault(x => x.Attribute?.Value == value);
if (found != null)
return (TEnum)Enum.Parse(typeof(TEnum), found.Member.Name);
return default(TEnum);
}
}
您应该将以下属性添加到您想要作为字符串的枚举中
[JsonConverter(typeof(JsonStringEnumConverter))]
您需要执行以下操作,因为描述属性不可序列化。
[DataContract]
public enum ControlSelectionType
{
[EnumMember(Value = "Not Applicable")]
NotApplicable = 1,
[EnumMember(Value = "Single Select Radio Buttons")]
SingleSelectRadioButtons = 2,
[EnumMember(Value = "Completely Different Display Text")]
SingleSelectDropDownList = 3,
}
public static string GetDescriptionFromEnumValue(Enum value)
{
EnumMemberAttribute attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(EnumMemberAttribute), false)
.SingleOrDefault() as EnumMemberAttribute;
return attribute == null ? value.ToString() : attribute.Value;}
容器定义
public class Container
{
public string Action { get; set; }
}
枚举定义
public enum Action {
Remove=1,
Add=2
}
视图中的代码
@Html.DropDownListFor(model => model.Action, typeof (Action))
扩展方法
/// <summary>
/// Returns an HTML select element for each property in the object that is represented by the specified expression using the given enumeration list items.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TProperty">The type of the value.</typeparam>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="expression">An expression that identifies the object that contains the properties to display.</param>
/// <param name="enumType">The type of the enum that fills the drop box list.</param>
/// <returns>An HTML select element for each property in the object that is represented by the expression.</returns>
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression, Type enumType)
{
var values = from Enum e in Enum.GetValues(enumType)
select new { Id = e, Name = e.ToString() };
return htmlHelper.DropDownListFor(expression, new SelectList(values, "Id", "Name"));
}
Newtonsoft.Json
库解决了这个问题。它修复了枚举问题,并使错误处理变得更好,并且它适用于 IIS 托管服务而不是自托管服务。它不需要任何更改或添加任何特殊内容到您的
DataContract
类中。代码相当多,因此您可以在 GitHub 上找到它:https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs 您必须向
Web.config
添加一些条目才能使其正常工作,您可以在此处查看示例文件:https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config