一、何为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

最新文章

  1. Android 通过httppost上传文本文件到服务器。
  2. PHP代码的执行
  3. 一张图看懂normal,static,sealed,abstract 的 区别
  4. 期望dp BZOJ3450+BZOJ4318
  5. 关于Beta分布、二项分布与Dirichlet分布、多项分布的关系
  6. GEOS库的学习之二:简单几何图形的创建
  7. string转换成color转
  8. git学习一
  9. eclipse 中创建maven web项目
  10. Linux下安装MySQLdb
  11. System.Web.HttpException: 无法向会话状态服务器发出会话状态请求
  12. p2.js物理引擎学习
  13. UCI机器学习数据库
  14. 【MySQL】20个经典面试题,全部答对月薪10k+
  15. TCP/IP----基本知识
  16. Leetcode_58_Length of Last Word
  17. Android Binder IPC详解-Android学习之旅(96)
  18. 《Thinking in Android 9.0 系统开发源码钻研录》
  19. canvas基础(一)
  20. C. cltt的幸运数LCAtarjan

热门文章

  1. ASP.NET Core and .NET Core Library Support
  2. docker下rabbitMQ高可用集群部署
  3. Linux服务器中木马(肉鸡)手工清除方法(转)
  4. 【Python】装饰器理解
  5. input 取消自动填充
  6. recovery.conf文件详解
  7. wordpress 生成自定义 meta box
  8. IOS开发 GCD介绍: 基本概念和Dispatch Queue
  9. Git详解之七 自定义Git
  10. 【Python】下载图片