Attribute的妙用 ---- 拦截器(过滤器)
一、何为Attribute
下面是微软官方对Attribute的解释:
公共语言运行时允许你添加类似关键字的描述声明,叫做Attributes,它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为。
通俗地理解,就是对目标对象(程序集、类、方法等)进行扩展,使得在运行时可以获取到被扩展对象的额外的信息,通过额外的信息来影响目标对象的行为。上面这句话纯粹是个人的理解,如有不妥希望指教。
二、使用Attribute
现在我有一个需求,创建一个包含 三个静态方法的类,如果某个方法被打上了标签,并且标签的Flag是1,那么就执行该方法,否则就不执行。看起来有点像过滤器,那么如何来实现这个小需求呢?首先要创建一个静态类MethodToRun,该类有三个静态方法分别是Run、Walk、Go,代码如下:

public class MethodToRun
{
public static void Run ()
{
Console.WriteLine("Run Run Hurry Up!");
Console.ReadLine();
} public static void Walk()
{
Console.WriteLine("Walk Slowly~");
Console.ReadLine();
} public static void Go()
{
Console.WriteLine("Go Go Go!");
Console.ReadLine();
}
}

好了,有了以上的类,接下来开始创建我们自定义的Attribute,为了和Property属性做个区分,我称之为特性。取个名字叫ExcuteAttribute,拥有一个Flag属性,代码如下:
[AttributeUsage(AttributeTargets.Method)]
public class ExcuteAttribute : Attribute
{
public int Flag { get; set; }
}
上述代码第一行指定了该特性作用的范围,回头看下我们之前说的一句话:
就是对目标对象(程序集、类、方法等)进行扩展,使得在运行时可以获取到被扩展对象的额外的信息,通过额外的信息来影响目标对象的行为。
这里的AttributeUsage中的参数AttributeTargets就是目标对象,它是一个枚举类型,具体的枚举如下:

//指定可以对它们应用属性的应用程序元素。
[ComVisible(true)]
[Flags]
public enum AttributeTargets
{
//可以对程序集应用属性。
Assembly = , //可以对模块应用属性。
Module = , //可以对类应用属性。
Class = , //可以对结构应用属性,即值类型。
Struct = , //可以对枚举应用属性。
Enum = , //可以对构造函数应用属性。
Constructor = , //可以对方法应用属性。
Method = , //可以对属性 (Property) 应用属性 (Attribute)。
Property = , //可以对字段应用属性。
Field = , //可以对事件应用属性。
Event = , //可以对接口应用属性。
Interface = , //可以对参数应用属性。
Parameter = , //可以对委托应用属性。
Delegate = , //可以对返回值应用属性。
ReturnValue = , //可以对泛型参数应用属性。
GenericParameter = , //可以对任何应用程序元素应用属性。
All =
}

标签创建完成了,我们修改一下MethodToRun这个类,加上标签,代码如下:

public class MethodToRun
{
[Excute(Flag =)]
public static void Run ()
{
Console.WriteLine("Run Run Hurry Up!");
Console.ReadLine();
} public static void Walk()
{
Console.WriteLine("Walk Slowly~");
Console.ReadLine();
} [Excute(Flag =)]
public static void Go()
{
Console.WriteLine("Go Go Go!");
Console.ReadLine();
}
}

其中,Run方法和Go方法加上了标签,且Flag的值分别为1和2,我们的需求是贴了标签并且Flag为1的方法被执行,下面来看下关键的调用代码:

class Program
{
static void Main(string[] args)
{
//获取MethodToRun类的静态方法集合
MethodInfo[] methods = typeof(MethodToRun).GetMethods(BindingFlags.Public|BindingFlags.Static);
foreach (var method in methods)
{
MethodInfo info = method;
//获取每个方法上的Attributes集合
var attributes = info.GetCustomAttributes(typeof(Attribute), false); foreach (var attri in attributes)
{
//如果自定义的标签是指定的标签则符合条件
if(attri is ExcuteAttribute)
{
ExcuteAttribute exe = attri as ExcuteAttribute;
//执行Flag为1的方法
if(exe.Flag == )
{
info.Invoke(null, null);
}
}
}
}
Console.ReadLine();
}
}

运行结果:

整个过程就是通过反射获取目标集合,本例子中的MethodToRun类中的静态方法(因为标签都贴在了静态方法中,且AttributeTargets指定的目标也是静态方法),然后获取方法上的自定义标签集合,相当于方法的额外的信息,通过这些额外的信息来影响方法的执行,现在再回头看看第一小节的粗体部分:
就是对目标对象(程序集、类、方法等)进行扩展,使得在运行时可以获取到被扩展对象的额外的信息,通过额外的信息来影响目标对象的行为。
以上是个人比较浅薄的理解,如果您有更深层次的理解,欢迎讨论,互相学习。
三、自己写拦截器
根据上面的表述,结合ASP.NET MVC常用的拦截器功能,自己实现一个极简的拦截器。首先定义一个接口ICustomFilter,包含两个接口方法,OnBeforeAction和OnAfterAction,代码如下:

/// <summary>
/// 自定义拦截器
/// </summary>
public interface ICustomFilter
{
//Action执行之前执行
void OnBeforeAction(); //Action执行之后执行
void OnAfterAction();
}

再定义一个Attribute实现该接口:

public class CustomFilterAttribute : Attribute, ICustomFilter
{
public void OnAfterAction()
{
Console.WriteLine("Action 执行之后进行拦截!");
} public void OnBeforeAction()
{
Console.WriteLine("Action 执行之前进行拦截!");
}
}

准备工作完成了,接下来给目标方法打上标签,修改下MethodToRun中的代码:

public class MethodToRun
{
[Excute(Flag =)]
public static void Run ()
{
Console.WriteLine("Run Run Hurry Up!");
Console.ReadLine();
} [CustomFilter]
public static void Walk()
{
Console.WriteLine("Walk Slowly~");
Console.ReadLine();
} [Excute(Flag =)]
public static void Go()
{
Console.WriteLine("Go Go Go!");
Console.ReadLine();
}
}

其中Walk方法添加了[CustomAttribute]特性,接下来看下调用代码是如何实现在Walk执行前后分别执行OnBeforeAction和OnAfterAction方法的,代码如下:

class Program
{
static void Main(string[] args)
{
MethodInfo[] methods = typeof(MethodToRun).GetMethods(BindingFlags.Public|BindingFlags.Static);
foreach (var method in methods)
{
MethodInfo info = method;
var attributes = info.GetCustomAttributes(typeof(Attribute), false); foreach (var attri in attributes)
{
if(attri is ExcuteAttribute)
{
ExcuteAttribute exe = attri as ExcuteAttribute;
if(exe.Flag == )
{
//info.Invoke(null, null);
}
}
//这里是重点
if(attri is CustomFilterAttribute)
{
CustomFilterAttribute cust = attri as CustomFilterAttribute;
cust.OnBeforeAction();
info.Invoke(null, null);
cust.OnAfterAction();
}
}
}
Console.ReadLine();
}
}

现在跑一下看看效果

上述小例子只是一个小小的应用,在.Net体系中,Attribute随处可见,其应用范围十分广泛。
出处:http://www.cnblogs.com/xhb-bky-blog/p/7840265.html
Attribute的妙用 ---- 拦截器(过滤器)的更多相关文章
- ava中拦截器 过滤器 监听器都有什么区别
过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts2的action进行业务逻辑,比如过滤掉非法u ...
- XML文档形式&JAVA抽象类和接口的区别&拦截器过滤器区别
XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? a: 两种形式 dtd schemab: 本质区别:schema本身是xml的,可以被XML解析器解析(这也是从DTD上发 ...
- spring拦截器-过滤器的区别
1. 理解 拦截器 :是在面向切面编程的时候,在你的 service 或者一个方法前调用一个方法,或者在方法后调用一个方法:比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业 ...
- java中拦截器 过滤器 监听器都有什么区别
过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts2的action进行业务逻辑,比如过滤掉非法u ...
- Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用
一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的 而在Spring中,基于Filter这种方式可以实现Bean预处理.后处理. 比如注入FilterRegistrationBean,然后 ...
- struts2 javaweb 过滤器、监听器 拦截器 原理
转: 过滤器.监听器 拦截器 过滤器 创建一个 Filter 只需两个步骤: (1)创建 Filter 处理类: (2)在 web.xml 文件中配置 Filter . 创建 Filter 必须实现 ...
- JavaWeb过滤器.监听器.拦截器-原理&区别-个人总结
对比项 拦截器 过滤器 机制 反射机制 函数回调 是否依赖servlet容器 是 否 请求处理 只能对action请求起作用 几乎所有的请求起作用 对action处理 可以访问action上下文.值栈 ...
- 过滤器(Filter)和拦截器(Interceptor)
过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序.它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求 ...
- 拦截器、过滤器、@Aspect 区别
1.需求场景 之前也有在文章写道 “拦截器\过滤器" 的区别,文章链接,在实际开发过程中,我们可能会遇到拦截请求参数的需求,在这我举个场景. 某一个接口的请求参数都是加密的,而请求参中还有一 ...
随机推荐
- JS/jQuery 遍历对象属性
Javascript For/In 循环: 循环遍历对象的属性 var person={fname:"John",lname:"Doe",age:25}; fo ...
- hdu3544找规律
如果x>1&&y>1,可以简化到其中一个为1的情况,这是等价的,当其中一个为1(假设为x),另一个一定能执行y-1次, 这是一个贪心问题,把所有的执行次数加起来比较就能得到 ...
- uva11626逆时针排序
给一个凸包,要求逆时针排序,刚开始一直因为极角排序就是逆时针的,所以一直wa,后来发现极角排序距离相同是,排的是随机的,所以要对末尾角度相同的点重新排一次 #include<map> #i ...
- Linux用root强制踢掉已登录用户;用fail2ban阻止ssh暴力破解root密码
Linux用root强制踢掉已登录用户 首先使用w命令查看所有在线用户: [root@VM_152_184_centos /]# w 20:50:14 up 9 days, 5:58, 3 use ...
- superset dashboard 设置自动刷新
因为发现了,自己制作了看板dashboard,却不会刷新,很奇怪. 那这样不是太傻了.难道要业务人员一个个去点吗? 一定有刷新的,然后和无头苍蝇在网上找了半天. 实际刷新的位置在这里. 具体设置有很多 ...
- laravel5.5种的Eloquent ORM的使用:
控制器方法: //Eloquent ORM的使用: public function orm1() { //all() /*$students=Student::all(); dd($students) ...
- Qt中使用ActiveX控件
(转自:http://blog.csdn.net/tingsking18/article/details/5403038) 在Qt中使用ActiveX控件 Qt的windows商业版本提供了Activ ...
- hdu 3032 Nim or not Nim? sg函数 难度:0
Nim or not Nim? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- 六.dbms_session(提供了使用PL/SQL实现ALTER SESSION命令)
1.概述 作用:提供了使用PL/SQL实现ALTER SESSION命令,SET ROLE命令和其他会话信息的方法 .2.包的组成 1).set_identifier说明:用于设置会话的客户ID号.语 ...
- python简单日志统计
业务场景:在一个目录里,有许多日志文件,里面是一条条的json数据,格式如下,为防止一个账号被多个ip使用,现在我想知道:哪些用户登录了哪些ip,和哪些ip登录了哪些用户,如果一个ip对应一个用户,就 ...