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.需求场景 之前也有在文章写道 “拦截器\过滤器" 的区别,文章链接,在实际开发过程中,我们可能会遇到拦截请求参数的需求,在这我举个场景. 某一个接口的请求参数都是加密的,而请求参中还有一 ...
随机推荐
- 内网 LAN IPv6 环境配置 H3C S5500 Huawei S5700
# 使能IPv6报文转发功能. <Sysname> system-view [Sysname] ipv6 # 使能DHCPv6服务器功能. <Sysname> system-v ...
- 【Python】什么是闭包
文章转载自:点这里 在 Python 中很多教材都没有提及什么是闭包,但在定义一个 Decorator 时,就已经用到闭包了.如果不理解什么是闭包,则不可能清晰掌握Decorator 装饰器. 要形成 ...
- SQL SERVER 正则替换
use pubdbgo IF OBJECT_ID(N'dbo.RegexReplace') IS NOT NULL DROP FUNCTION dbo.RegexReplace GO --开始创建正则 ...
- nfc功能读写 demo
点此下载//这个demo是把这个程序作为一个手机启动选择的,只要一扫到卡片就会跳转到这个Activity. 只在当前Activity中有效参考:http://blog.csdn.net/zoeice/ ...
- Struts13---Ognl
模拟初始化的jsp页面 <body> <a href="user/login">登录</a> </body> public clas ...
- APUE学习笔记——10信号——信号接口函数 signal 和 sigaction
signal函数 signal函数是早起Unix系统的信号接口,早期系统中提供不可靠的信号机制.在后来的分支中,部分系统使用原来的不可靠机制定义signal函数,如 Solaris 10 .而 ...
- Eclipse快捷键详细解析
android开发中常用的Eclipse快捷键详细解析 1.查看快捷键定义的地方 Window->Preferences->General->Keys. 2.更改启动页 在Andro ...
- 微信小程序自定义tabbar的问题
个人感觉小程序的tab样式自定义的能力有所欠缺,不够美观,于是今天自己diy了一个tab 测试的时候发现,无论是使用navigator跳转(会出现点击的效果)还是用bindtap(触摸),因为没有定义 ...
- 开启 Android WebView 的安全浏览模式
Hybrid App(混合式开发)已经是每一个商业应用都会使用的开发手段.其最大的优势就是将一些可动态更新的内容页面使用 H5 开发,然后借用移动端原生系统提供的 WebView 控件加载进来.这种方 ...
- CBUS转MQTT
CBUS转MQTT,楼宇控制协议通过迈思德网关转MQTT