[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含17953字,纯文字阅读大概需要26分钟。
内容图文
![[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper](/upload/InfoBanner/zyjiaocheng/1069/31c80a99ebbf4b2f874fab076c8beb4f.jpg)
一、需求
我们在开发中经常会遇到一些枚举,而且这些枚举类型可能会在表单中的下拉中,或者单选按钮中会用到等。
这样用是没问题的,但是用过的人都知道一个问题,就是枚举的命名问题,当然有很多人枚举直接中文命名,我是不推荐这种命名规则,因为实在不够友好。
那有没有可以不用中文命名,而且可以显示中文的方法呢。答案是肯定的。
二、特性解决枚举命名问题
那就是用特性解决命名问题,这样的话既可以枚举用英文命名,显示又可以是中文的,岂不两全其美。
/// <summary> /// 性别 /// </summary> public enum Gender { /// <summary> /// 女性 /// </summary> [Description("女性")] Female = 1, ///<summary>/// 男性 ///</summary> [Description("男性")] Male = 2, ///<summary>/// 未知 ///</summary> [Description("未知")] Unknown = 3, ///<summary>/// 人妖 ///</summary> [Description("人妖")] Demon = 4 }
1、新建枚举的特性类
首先我们需要新建枚举的特性,用来描述枚举,这样既可以解决枚举的命名问题,又可以解决枚举的显示问题。
我们在下拉框或者单选按钮上显示各个枚举项,可能会出现一些排序问题,所以在枚举的特性上不仅有显示的名称还有排序。
/// <summary> /// 枚举特性 /// </summary> [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] publicclass DescriptionAttribute : Attribute { ///<summary>/// 排序 ///</summary>publicint Order { get; set; } ///<summary>/// 名称 ///</summary>publicstring Name { get; set; } ///<summary>/// 显示自定义描述名称 ///</summary>///<param name="name">名称</param>public DescriptionAttribute(string name) { Name = name; } ///<summary>/// 显示自定义名称 ///</summary>///<param name="name">名称</param>///<param name="order">排序</param>public DescriptionAttribute(string name, int order) { Name = name; Order = order; } }
新建好枚举的特性类以后,我们就可以在枚举的字段上添加自定义的特性Description
/// <summary> /// 性别 /// </summary> public enum Gender { /// <summary> /// 女性 /// </summary> [Description("女性", 2)] Female = 1, ///<summary>/// 男性 ///</summary> [Description("男性", 1)] Male = 2, ///<summary>/// 未知 ///</summary> [Description("未知", 3)] Unknown = 3, ///<summary>/// 人妖 ///</summary> [Description("人妖", 4)] Demon = 4 }
特性第一个参数为名称,第二个为排序(int 类型,正序),这就是就是我们新建枚举时在需要显示和枚举名称不一样的枚举字段上添加即可。这个Gender枚举,在后面文章中会一直用到(Gender)。
2、新建枚举扩展方法获取枚举特性的描述
我们前面的工作已经把特性和在枚举上添加特性已经完成了,后面我们需要的就是要获取我们添加的描述和排序。
/// <summary> /// 枚举帮助类 /// </summary> public static class EnumTools { /// <summary> /// 获取当前枚举值的描述 /// </summary> /// <param name="value"></param> /// <returns></returns> public static string GetDescription(this Enum value) { int order; return GetDescription(value, out order); } ///<summary>/// 获取当前枚举值的描述和排序 ///</summary>///<param name="value"></param>///<param name="order"></param>///<returns></returns>publicstaticstring GetDescription(this Enum value, outint order) { string description = string.Empty; Type type = value.GetType(); // 获取枚举 FieldInfo fieldInfo = type.GetField(value.ToString()); // 获取枚举自定义的特性DescriptionAttributeobject[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); DescriptionAttribute attr = (DescriptionAttribute)attrs.FirstOrDefault(a => a is DescriptionAttribute); order = 0; description = fieldInfo.Name; if (attr != null) { order = attr.Order; description = attr.Name; } return description; } }
3、获取枚举描述和排序
至此:我们可以很容易获取到枚举添加的特性描述和排序。
var des = Gender.Male.GetDescription(); // des = “男性”var name = Gender.Male.ToString(); // name= "Male"var key = (int)Gender.Male; // key = 2int order; var des1 = Gender.Female.GetDescription(out order); // des1 = “女性”, order= 2
这样我们就很好的解决了枚举命名问题, 可以很容易的获取到枚举的描述信息,也就是要显示的信息。但是我们需要的是一次性可以查询全部的枚举信息,以便我们进行显示。
三、获取所有枚举的描述和值,以便循环使用
我们已经可以很容易的获取到枚举的值,名称和描述了,所以后面的就很简单了。
/// <summary> /// 枚举帮助类 /// </summary> public static class EnumTools { /// <summary> /// 获取当前枚举的所有描述 /// </summary> /// <param name="value"></param> /// <returns></returns> public static List<KeyValuePair<int, string>> GetAll<T>() { return GetAll(typeof(T)); } ///<summary>/// 获取所有的枚举描述和值 ///</summary>///<param name="type"></param>///<returns></returns>publicstatic List<KeyValuePair<int, string>> GetAll(Type type) { List<EnumToolsModel> list = new List<EnumToolsModel>(); // 循环枚举获取所有的Fieldsforeach (var field in type.GetFields()) { // 如果是枚举类型if (field.FieldType.IsEnum) { object tmp = field.GetValue(null); Enum enumValue = (Enum)tmp; int intValue = Convert.ToInt32(enumValue); int order; string showName = enumValue.GetDescription(out order); // 获取描述和排序 list.Add(new EnumToolsModel { Key = intValue, Name = showName, Order = order }); } } // 排序并转成KeyValue返回return list.OrderBy(i => i.Order).Select(i => new KeyValuePair<int, string>(i.Key, i.Name)).ToList(); } }
调用:这样我们就很容易的获取枚举所有字段的描述,如我们需要在cshtml中调用
< select class ="form-control" > @{ var genders = EnumTools.GetAll < Gender > ();} // 或者EnumTools.GetAll<>(Typeof(Gender)) @foreach (var item in genders) { < option value ="@item.Key" > @item.Value </ option > } </ select >
生成的html为:
< select class ="form-control" > < option value ="2" >男性</option><option value="1">女性</option><option value="3">未知</option><option value="4">人妖</option></select>
这样我们就已顺利的解决了枚举的命名以及排序显示等问题。
四、枚举特性扩展至HtmlHelper
我们已经解决了枚举的命名以及排序显示问题,但是我们想做的更好,比如每次都要写一个foreach获取所有的枚举然后在判断默认值和哪个相等,循环遍历,周而复始,重复造轮子,bad code。所以我们要进行封装,封装成与 @Html.DropDownList一样好用的HtmlHelper扩展。
/// <summary> /// 枚举下拉 /// </summary> /// <typeparam name="T"> 枚举类型 </typeparam> /// <param name="html"></param> /// <param name="htmlAttributes"></param> /// <returns></returns> public static MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, object htmlAttributes = null) { return html.EnumToolsSelect(typeof(T), int.MaxValue, htmlAttributes); } ///<summary>/// 枚举下拉 ///</summary>///<typeparam name="T">枚举类型</typeparam>///<param name="html"></param>///<param name="selectedValue">选择项</param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, int selectedValue, object htmlAttributes = null) { return html.EnumToolsSelect(typeof(T), selectedValue, htmlAttributes); } ///<summary>/// 枚举下拉 ///</summary>///<typeparam name="T">枚举类型</typeparam>///<param name="html"></param>///<param name="selectedValue">选择项</param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, T selectedValue, object htmlAttributes = null) { return html.EnumToolsSelect(typeof(T), Convert.ToInt32(selectedValue), htmlAttributes); } ///<summary>/// 枚举下拉 ///</summary>///<param name="html"></param>///<param name="enumType">枚举类型</param>///<param name="selectedValue">选择项</param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelect(this HtmlHelper html, Type enumType, int selectedValue, object htmlAttributes = null) { // 创建标签 TagBuilder tag = new TagBuilder("select"); // 添加自定义标签if (htmlAttributes != null) { RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); tag.MergeAttributes(htmlAttr); } // 创建option集合 StringBuilder options = new StringBuilder(); foreach (var item in GetAll(enumType)) { // 创建option TagBuilder option = new TagBuilder("option"); // 添加值 option.MergeAttribute("value", item.Key.ToString()); // 设置选择项if (item.Key == selectedValue) { option.MergeAttribute("selected", "selected"); } // 设置option option.SetInnerText(item.Value); options.Append(option.ToString()); } tag.InnerHtml = options.ToString(); // 返回MVCHtmlStringreturn MvcHtmlString.Create(tag.ToString()); }
然后调用
@(Html.EnumToolsSelect<Gender>()) @(Html.EnumToolsSelect<Gender>(Gender.Unknown)) @(Html.EnumToolsSelect<Gender>(1)) @(Html.EnumToolsSelect<Gender>(Gender.Female, new { @class = "form-control" })) @(Html.EnumToolsSelect(typeof(Gender), 1)
这样就可以生成你所需要的下拉框的html,一行代码就可以解决复杂的枚举下拉。
你以为就这样结束了吗,很明显没有,因为不是我风格,我的风格是继续封装。
五、枚举特性扩展至HtmlHelper Model
这个可能有很多不会陌生,因为很多HtmlHelper都有一个For结尾的,如@Html.DropDownListFor等等,那我们也要有For结尾的,要不然都跟不上潮流了。
关于For的一些扩展和没有For的扩展的区别,简单来说带For就是和Model一起用的,如:@Html.TextBoxFor(i => i.Name)
这样就可以更加一步的封装,如Id,name,model的Name值以及验证等等。
话不多说,直接代码
/// <summary> /// 下拉枚举 /// </summary> /// <typeparam name="TModel"> Model </typeparam> /// <typeparam name="TProperty"> 属性 </typeparam> /// <param name="htmlHelper"></param> /// <param name="expression"></param> /// <param name="htmlAttributes"></param> /// <returns></returns> public static MvcHtmlString EnumToolsSelectFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null) { // 获取元数据meta ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); Type enumType = modelMetadata.ModelType; // 设置id name的属性值var rvd = new RouteValueDictionary { { "id", modelMetadata.PropertyName }, { "name", modelMetadata.PropertyName } }; // 添加自定义属性if (htmlAttributes != null) { RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); foreach (var item in htmlAttr) { rvd.Add(item.Key, item.Value); } } // 获取验证信息 IDictionary<string, object> validationAttributes = htmlHelper.GetUnobtrusiveValidationAttributes(modelMetadata.PropertyName, modelMetadata); // 添加至自定义属性if (validationAttributes != null) { foreach (var item in validationAttributes) { rvd.Add(item.Key, item.Value); } } return htmlHelper.EnumToolsSelect(enumType, Convert.ToInt32(modelMetadata.Model), rvd); }
关于使用:
首先我们需要返回view时需要返回Model
public class HomeController : Controller { public ActionResult Index() { return View(new Person { Age = 1, Name = "Emrys", Gender = Gender.Male }); } } publicclass Person { publicstring Name { get; set; } publicint Age { get; set; } public Gender Gender { get; set; } }
cshtm调用
@Html.EnumToolsSelectFor(i => i.Gender)
生成html代码
< select data-val ="true" data-val-required ="Gender 字段是必需的。" id ="Gender" name ="Gender" > < option selected ="selected" value ="2" >男性</option><option value="1">女性</option><option value="3">未知</option><option value="4">人妖</option></select>
六、全部枚举特性和HtmlHelper代码
![技术分享](/img/jia.gif)
![技术分享](/img/jian.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Web.Mvc; using System.Web.Routing; namespace Emrys.EnumTools { /// <summary> /// 枚举帮助类 /// </summary> public static class EnumTools { /// <summary> /// 获取当前枚举值的描述 /// </summary> /// <param name="value"></param> /// <returns></returns> public static string GetDescription(this Enum value) { int order; return GetDescription(value, out order); } ///<summary>/// 获取当前枚举值的描述和排序 ///</summary>///<param name="value"></param>///<param name="order"></param>///<returns></returns>publicstaticstring GetDescription(this Enum value, outint order) { string description = string.Empty; Type type = value.GetType(); // 获取枚举 FieldInfo fieldInfo = type.GetField(value.ToString()); // 获取枚举自定义的特性DescriptionAttributeobject[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); DescriptionAttribute attr = (DescriptionAttribute)attrs.FirstOrDefault(a => a is DescriptionAttribute); order = 0; description = fieldInfo.Name; if (attr != null) { order = attr.Order; description = attr.Name; } return description; } ///<summary>/// 获取当前枚举的所有描述 ///</summary>///<param name="value"></param>///<returns></returns>publicstatic List<KeyValuePair<int, string>> GetAll<T>() { return GetAll(typeof(T)); } ///<summary>/// 获取所有的枚举描述和值 ///</summary>///<param name="type"></param>///<returns></returns>publicstatic List<KeyValuePair<int, string>> GetAll(Type type) { List<EnumToolsModel> list = new List<EnumToolsModel>(); // 循环枚举获取所有的Fieldsforeach (var field in type.GetFields()) { // 如果是枚举类型if (field.FieldType.IsEnum) { object tmp = field.GetValue(null); Enum enumValue = (Enum)tmp; int intValue = Convert.ToInt32(enumValue); int order; string showName = enumValue.GetDescription(out order); // 获取描述和排序 list.Add(new EnumToolsModel { Key = intValue, Name = showName, Order = order }); } } // 排序并转成KeyValue返回return list.OrderBy(i => i.Order).Select(i => new KeyValuePair<int, string>(i.Key, i.Name)).ToList(); } ///<summary>/// 枚举下拉 ///</summary>///<typeparam name="T">枚举类型</typeparam>///<param name="html"></param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, object htmlAttributes = null) { return html.EnumToolsSelect(typeof(T), int.MaxValue, htmlAttributes); } ///<summary>/// 枚举下拉 ///</summary>///<typeparam name="T">枚举类型</typeparam>///<param name="html"></param>///<param name="selectedValue">选择项</param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, int selectedValue, object htmlAttributes = null) { return html.EnumToolsSelect(typeof(T), selectedValue, htmlAttributes); } ///<summary>/// 枚举下拉 ///</summary>///<typeparam name="T">枚举类型</typeparam>///<param name="html"></param>///<param name="selectedValue">选择项</param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, T selectedValue, object htmlAttributes = null) { return html.EnumToolsSelect(typeof(T), Convert.ToInt32(selectedValue), htmlAttributes); } ///<summary>/// 枚举下拉 ///</summary>///<param name="html"></param>///<param name="enumType">枚举类型</param>///<param name="selectedValue">选择项</param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelect(this HtmlHelper html, Type enumType, int selectedValue, object htmlAttributes = null) { // 创建标签 TagBuilder tag = new TagBuilder("select"); // 添加自定义标签if (htmlAttributes != null) { RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); tag.MergeAttributes(htmlAttr); } // 创建option集合 StringBuilder options = new StringBuilder(); foreach (var item in GetAll(enumType)) { // 创建option TagBuilder option = new TagBuilder("option"); // 添加值 option.MergeAttribute("value", item.Key.ToString()); // 设置选择项if (item.Key == selectedValue) { option.MergeAttribute("selected", "selected"); } // 设置option option.SetInnerText(item.Value); options.Append(option.ToString()); } tag.InnerHtml = options.ToString(); // 返回MVCHtmlStringreturn MvcHtmlString.Create(tag.ToString()); } ///<summary>/// 下拉枚举 ///</summary>///<typeparam name="TModel">Model</typeparam>///<typeparam name="TProperty">属性</typeparam>///<param name="htmlHelper"></param>///<param name="expression"></param>///<param name="htmlAttributes"></param>///<returns></returns>publicstatic MvcHtmlString EnumToolsSelectFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null) { // 获取元数据meta ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); Type enumType = modelMetadata.ModelType; // 设置id name的属性值var rvd = new RouteValueDictionary { { "id", modelMetadata.PropertyName }, { "name", modelMetadata.PropertyName } }; // 添加自定义属性if (htmlAttributes != null) { RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); foreach (var item in htmlAttr) { rvd.Add(item.Key, item.Value); } } // 获取验证信息 IDictionary<string, object> validationAttributes = htmlHelper.GetUnobtrusiveValidationAttributes(modelMetadata.PropertyName, modelMetadata); // 添加至自定义属性if (validationAttributes != null) { foreach (var item in validationAttributes) { rvd.Add(item.Key, item.Value); } } return htmlHelper.EnumToolsSelect(enumType, Convert.ToInt32(modelMetadata.Model), rvd); } } ///<summary>/// 枚举特性 ///</summary> [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] publicclass DescriptionAttribute : Attribute { ///<summary>/// 排序 ///</summary>publicint Order { get; set; } ///<summary>/// 名称 ///</summary>publicstring Name { get; set; } ///<summary>/// 显示自定义描述名称 ///</summary>///<param name="name">名称</param>public DescriptionAttribute(string name) { Name = name; } ///<summary>/// 显示自定义名称 ///</summary>///<param name="name">名称</param>///<param name="order">排序</param>public DescriptionAttribute(string name, int order) { Name = name; Order = order; } } ///<summary>/// 枚举Model ///</summary>partialclass EnumToolsModel { publicint Order { get; set; } publicstring Name { get; set; } publicint Key { get; set; } } }
最后望对各位有所帮助,本文原创,欢迎拍砖和推荐。
Github:https://github.com/Emrys5/Asp.MVC-03-Enum-rename-htmlhelper
原文:http://www.cnblogs.com/emrys5/p/Enum-rename-htmlhelper.html
内容总结
以上是互联网集市为您收集整理的[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper全部内容,希望文章能够帮你解决[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。