一、何为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的妙用的更多相关文章

  1. C#基础---Attribute(标签) 和 reflect(反射) 应用二

    以前我有写过一篇有关,打标签和反射的应用,主要用于类中字段的验证.下面是连接 C#基础---Attribute(标签) 和 reflect(反射) 应用. 这个项目迭代发现公司项目里面发现老代码对业务 ...

  2. C#基础---Attribute(标签) 和 reflect(反射) 应用

    1.Attribute的定义与作用: 公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法和属性等.Attributes和Micros ...

  3. Attribute的妙用 ---- 拦截器(过滤器)

    一.何为Attribute 下面是微软官方对Attribute的解释: 公共语言运行时允许你添加类似关键字的描述声明,叫做Attributes,它对程序中的元素进行标注,如类型.字段.方法和属性等.A ...

  4. Java基础之枚举妙用

    对于枚举,初学Java的时候可能我们就已经接触过了,但是在毕业前,其实一直都不知道真正工作里面枚举是怎么用的,枚举有什么用?接下来,博主就介绍枚举在实际工作中的一种使用场景,本文只适合初级的小菜鸟看哈 ...

  5. .NET Attribute在数据校验上的应用

    Attribute(特性)的概念不在此赘述了,相信有点.NET基础的开发人员都明白,用过Attribute的人也不在少数,毕竟很多框架都提供自定义的属性,类似于Newtonsoft.JSON中Json ...

  6. C#基础笔记---浅谈XML读取以及简单的ORM实现

    背景: 在开发ASP.NETMVC4 项目中,虽然web.config配置满足了大部分需求,不过对于某些特定业务,我们有时候需要添加新的配置文件来记录配置信息,那么XML文件配置无疑是我们选择的一个方 ...

  7. C#基础---浅谈XML读取以及简单的ORM实现

    背景: 在开发ASP.NETMVC4 项目中,虽然web.config配置满足了大部分需求,不过对于某些特定业务,我们有时候需要添加新的配置文件来记录配置信息,那么XML文件配置无疑是我们选择的一个方 ...

  8. C#基础系列——Attribute特性使用

    前言:上篇 C#基础系列——反射笔记 总结了下反射得基础用法,这章我们来看看C#的另一个基础技术——特性. 1.什么是特性:就博主的理解,特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属 ...

  9. 妙味课堂——HTML+CSS基础笔记

    妙味课堂的课程讲得非常的清楚,受益匪浅.先把HTML和CSS基础课程部分视频的学习笔记记录如下: padding #PS基础 ##前端需要的PS技能 - PS技能(前端需要):切图.修图.测量 - P ...

随机推荐

  1. Redis Windows版安装详解

    一.下载Redis Redis下载有两个途径一是官网.二是Github,由于Redis官方只支持Linux系统,所以官网是没有Windows版本的,不过微软开源团队维护了一份所以我们可以使用这个. 官 ...

  2. HDU1068 二分匹配 独立集

    前边和后边性别不同!!!不然NP了 Girls and Boys Problem Description the second year of the university somebody star ...

  3. There is no getter for property named xxx' in 'class java.lang.xxx'

    在xxxMapper.xml我们使用sql片段来提高sql代码的复用性,当时新手传入参数时常常出现这样的错误: There is no getter for property named xxx' i ...

  4. dotweb框架之旅 [二] - 常用对象-App(dotweb)

    dotweb属于一个Web框架,希望通过框架行为,帮助开发人员快速构建Web应用,提升开发效率,减少不必要的代码臃肿. dotweb包含以下几个常用对象: App(dotweb) App容器,为Web ...

  5. 51nod 1522 上下序列

    题目描述 现在有1到n的整数,每一种有两个.要求把他们排在一排,排成一个2*n长度的序列,排列的要求是从左到右看,先是不降,然后是不升. 特别的,也可以只由不降序列,或者不升序列构成. 例如,下面这些 ...

  6. Hadoop(七)HDFS容错机制详解

    前言 HDFS(Hadoop Distributed File System)是一个分布式文件系统.它具有高容错性并提供了高吞吐量的数据访问,非常适合大规模数据集上的应用,它提供了一个高度容错性和高吞 ...

  7. win10 uwp 判断文件存在

    本文主要翻译http://stackoverflow.com/questions/37119464/uwp-check-if-file-exists/37152526#37152526 我们有多种方法 ...

  8. springcloud干货之服务消费者(ribbon)

    本章介绍springcloud中的服务消费者 springcloud服务调用方式有两种实现方式: 1,restTemplate+ribbon, 2,feign 本来想一篇讲完,发现篇幅有点长,所以本章 ...

  9. 2年Java开发工作经验面试总结

    最近换了个公司,从三月底开始面,面到四月底,面了有快二十家公司.我是一个喜欢总结经验的人,每经过一场面试,我在回来的路上都会仔细回想今天哪些问题可以答的更好,或者哪些问题是自己之前没遇到过的,或者是哪 ...

  10. 【转】DMA和cache一致性

    DMA和cache一致性问题 Cache原理 CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器,它的容量比内存小的多但是交换速度却比内存要快得多.缓存的出现主要是为了解决CPU ...