[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper
一、需求
我们在开发中经常会遇到一些枚举,而且这些枚举类型可能会在表单中的下拉中,或者单选按钮中会用到等。
这样用是没问题的,但是用过的人都知道一个问题,就是枚举的命名问题,当然有很多人枚举直接中文命名,我是不推荐这种命名规则,因为实在不够友好。
那有没有可以不用中文命名,而且可以显示中文的方法呢。答案是肯定的。
二、特性解决枚举命名问题
那就是用特性解决命名问题,这样的话既可以枚举用英文命名,显示又可以是中文的,岂不两全其美。
/// <summary>
/// 性别
/// </summary>
public enum Gender
{
/// <summary>
/// 女性
/// </summary>
[Description("女性")]
Female = , /// <summary>
/// 男性
/// </summary>
[Description("男性")]
Male = , /// <summary>
/// 未知
/// </summary>
[Description("未知")]
Unknown = , /// <summary>
/// 人妖
/// </summary>
[Description("人妖")]
Demon =
}
1、新建枚举的特性类
首先我们需要新建枚举的特性,用来描述枚举,这样既可以解决枚举的命名问题,又可以解决枚举的显示问题。
我们在下拉框或者单选按钮上显示各个枚举项,可能会出现一些排序问题,所以在枚举的特性上不仅有显示的名称还有排序。
/// <summary>
/// 枚举特性
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class DescriptionAttribute : Attribute
{
/// <summary>
/// 排序
/// </summary>
public int Order { get; set; } /// <summary>
/// 名称
/// </summary>
public string 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("女性", )]
Female = , /// <summary>
/// 男性
/// </summary>
[Description("男性", )]
Male = , /// <summary>
/// 未知
/// </summary>
[Description("未知", )]
Unknown = , /// <summary>
/// 人妖
/// </summary>
[Description("人妖", )]
Demon =
}
特性第一个参数为名称,第二个为排序(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>
public static string GetDescription(this Enum value, out int order)
{
string description = string.Empty; Type type = value.GetType(); // 获取枚举
FieldInfo fieldInfo = type.GetField(value.ToString()); // 获取枚举自定义的特性DescriptionAttribute
object[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
DescriptionAttribute attr = (DescriptionAttribute)attrs.FirstOrDefault(a => a is DescriptionAttribute); order = ;
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 = 2 int 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>
public static List<KeyValuePair<int, string>> GetAll(Type type)
{ List<EnumToolsModel> list = new List<EnumToolsModel>(); // 循环枚举获取所有的Fields
foreach (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>
public static 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>
public static 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>
public static 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(); // 返回MVCHtmlString
return MvcHtmlString.Create(tag.ToString()); }
然后调用
@(Html.EnumToolsSelect<Gender>())
@(Html.EnumToolsSelect<Gender>(Gender.Unknown))
@(Html.EnumToolsSelect<Gender>())
@(Html.EnumToolsSelect<Gender>(Gender.Female, new { @class = "form-control" }))
@(Html.EnumToolsSelect(typeof(Gender), )
这样就可以生成你所需要的下拉框的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 = , Name = "Emrys", Gender = Gender.Male });
} } public class Person
{
public string Name { get; set; }
public int 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代码
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>
public static string GetDescription(this Enum value, out int order)
{
string description = string.Empty; Type type = value.GetType(); // 获取枚举
FieldInfo fieldInfo = type.GetField(value.ToString()); // 获取枚举自定义的特性DescriptionAttribute
object[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
DescriptionAttribute attr = (DescriptionAttribute)attrs.FirstOrDefault(a => a is DescriptionAttribute); order = ;
description = fieldInfo.Name; if (attr != null)
{
order = attr.Order;
description = attr.Name;
}
return description; } /// <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>
public static List<KeyValuePair<int, string>> GetAll(Type type)
{ List<EnumToolsModel> list = new List<EnumToolsModel>(); // 循环枚举获取所有的Fields
foreach (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>
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>
public static 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>
public static 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>
public static 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(); // 返回MVCHtmlString
return 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>
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);
}
} /// <summary>
/// 枚举特性
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class DescriptionAttribute : Attribute
{
/// <summary>
/// 排序
/// </summary>
public int Order { get; set; } /// <summary>
/// 名称
/// </summary>
public string 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>
partial class EnumToolsModel
{
public int Order { get; set; }
public string Name { get; set; }
public int Key { get; set; }
}
}
最后望对各位有所帮助,本文原创,欢迎拍砖和推荐。
Github:https://github.com/Emrys5/Asp.MVC-03-Enum-rename-htmlhelper
系列课程
- [asp.net mvc 奇淫巧技] 01 - 封装上下文 - 在View中获取自定义的上下文
- [asp.net mvc 奇淫巧技] 02 - 巧用Razor引擎在Action内生成Html代码
- [asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper
- [asp.net mvc 奇淫巧技] 04 - 你真的会用Action的模型绑定吗?
- [asp.net mvc 奇淫巧技] 05 - 扩展ScriptBundle,支持混淆加密javascript
- [asp.net mvc 奇淫巧技] 06 - 也许你的项目同一个用户的请求都是同步的
[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper的更多相关文章
- [asp.net mvc 奇淫巧技] 01 - 封装上下文 - 在View中获取自定义的上下文
我们在asp.net 开发中已经封装了最强大的HttpContext,我们可以在HttpContext中可以获取到几乎任何想获取的东西,也可以在HttpContext写入需要返回客户端的信息.但是这些 ...
- [asp.net mvc 奇淫巧技] 02 - 巧用Razor引擎在Action内生成Html代码
在web开发中经常会遇到在内部代码中获取Html,这些Html是需要和数据进行一起渲染.并不是直接把Html代码返回给客户端.这样的做法有很多应用场景,例如分页.Ajax一次性获取几段Html片段.生 ...
- [asp.net mvc 奇淫巧技] 04 - 你真的会用Action的模型绑定吗?
在QQ群或者一些程序的交流平台,经常会有人问:我怎么传一个数组在Action中接收.我传的数组为什么Action的model中接收不到.或者我在ajax的data中设置了一些数组,为什么后台还是接收不 ...
- [asp.net mvc 奇淫巧技] 05 - 扩展ScriptBundle,支持混淆加密javascript
一.需求: 在web开发中,经常会处理javascript的一些问题,其中就包括js的压缩,合并,发布版本以及混淆加密等等问题.在asp.net 开发中我们使用ScriptBundle已经可以解决ja ...
- [asp.net mvc 奇淫巧技] 06 - 也许你的项目同一个用户的请求都是同步的
一.感慨 很久前看到一篇博客中有句话大致的意思是:“asp.net 程序性能低下的主要原因是开发人员技术参差不齐”,当时看到这句话不以为然,然而时间过的越久接触的.net 开发人员越多就越认同这句话: ...
- ASP.NET Core 奇淫技巧之伪属性注入
一.前言 开局先唠嗑一下,许久未曾更新博客,一直在调整自己的状态,去年是我的本命年,或许是应验了本命年的多灾多难,过得十分不顺,不论是生活上还是工作上.还好当我度过了所谓的本命年后,许多事情都在慢慢变 ...
- [javascript 实践篇]——那些你不知道的“奇淫巧技”
1. 空(null, undefined)验证 刚开始,我是比较蠢的验证(我还真是这样子验证的) if (variable1 !== null || variable1 !== undefined | ...
- Asp.net MVC的Model Binder工作流程以及扩展方法(2) - Binder Attribute
上篇文章中分析了Custom Binder的弊端: 由于Custom Binder是和具体的类型相关,比如指定类型A由我们的Custom Binder解析,那么导致系统运行中的所有Action的访问参 ...
- ASP.NET MVC中对Model进行分步验证的解决方法
原文:ASP.NET MVC中对Model进行分步验证的解决方法 在我之前的文章:ASP.NET MVC2.0结合WF4.0实现用户多步注册流程中将一个用户的注册分成了四步,而这四个步骤都是在完善一个 ...
随机推荐
- 对quartz定时任务的初步认识
已经好久没有写技术博文了,今天就谈一谈我前两天自学的quartz定时任务吧,我对quartz定时任务的理解,就是可以设定一个时间,然后呢,在这个时间到的时候,去执行业务逻辑,这是我的简单理解,接下来看 ...
- Historical节点
Historical节点 Historical 节点的作用是,load 历史数据提供查询. 运行类 io.druid.cli.Main server historical 装载和保存Segments ...
- yii框架后台过滤器的使用 安全防护
Yii过滤器简介 过滤器是一段代码,可被配置在控制器动作执行之前或之后执行.例如, 访问控制过滤器将被执行以确保在执行请求的动作之前用户已通过身份验证:性能过滤器可用于测量控制器执行所用的时间. 一个 ...
- JavaScript中的数据结构及实战系列(2):栈
开题: 不冒任何险,什么都不做,什么也不会有,什么也不是. 本文目录 栈介绍: JavaScript实现栈: 栈的应用: 栈介绍: 和队列一样,栈也是一种表结构,但是和队列的"先进先出&qu ...
- 篇4 安卓app自动化测试-Appium API进阶
篇4 安卓app自动化测试-Appium API进阶 --lamecho辣么丑 1.1概要 大家好! 我是lamecho(辣么丑),今天是<安卓app自动化测试& ...
- ashMap源码阅读与解析
目录结构 导入语 HashMap构造方法 put()方法解析 addEntry()方法解析 get()方法解析 remove()解析 HashMap如何进行遍历 导入语 HashMap是我们最常见也是 ...
- bzoj2125 最短路
Description 给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径. Input 输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个 ...
- [ext4]空间管理 - 分配机制
在Ext4系统中,存在很多分配策略,比如预分配.多块分配.延迟分配等 Prealloc预分配 在ext4系统中,对于小文件和大文件的空间申请请求,都有不同的分配策略.对用小文件的空间请求,e ...
- 为什么要用Handler ?
我的理解,Handler的好处之一就是配合子线程处理数据之后控制UI的显示. 如下是http://www.cnblogs.com/sydeveloper/p/3312865.html的完美解释: 当应 ...
- DTCMS插件的制作实例电子资源管理(三)前台模板页编写
总目录 插件目录结构(一) Admin后台页面编写(二) 前台模板页编写(三) URL重写(四) 本实例旨在以一个实际的项目中的例子来介绍如何在dtcms中制作插件,本系列文章非入门教程,部分逻辑实现 ...