一、何为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. java数据库编程之初始Mysql

    2.3:命令行连接mySql 2.3.1:检查是否启动服务 步骤:计算机-----管理------服务和应用程序-------服务---搜索mysql右键启动服务 2.3.2:命令行方式连接数据库 步 ...

  2. 使用python操作mysql

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7643047.html 作者:窗户 Q ...

  3. Gate One——用web展示Terminal(安装)

    Gate One可以用web来展示Terminal,虽然存在一些小缺陷,基本功能都还可以的,有兴趣的可以折腾一下. 安装环境: 系统:RHEL 6.1 ,系统自带python 2.6.6 下载需要安装 ...

  4. SQLServer中SQL语句与可执行二进制语句

    SQLServer可以执行正常SQL语句也可以执行被转换的二进制语句,一般会用此方法进行数据库注入操作,骗过基本的字符过滤 --将二进制格式转为普通SQL语句 ) = 0x53454C45435420 ...

  5. WPF Popup全屏 弹出方法。解决只显示75%的问题。

    WPF Popup全屏 弹出方法.解决只显示75%的问题.   WPF 中 Popup 有一个特点.当Popup的高度超过屏幕的75%的时候,只显示75%的高度. 如下代码: <Window x ...

  6. 中秋H5,这篇脑洞开的可以!

    案例:嫦娥--寻开心出品:凯迪仕 1.内容:这是一支视频类H5案例.Loading完毕进入页面,首屏提示案例最佳观看方式为先锁屏再横屏.点击开始按钮播放视频,视频讲述"葫芦娃"缠着 ...

  7. win10 uwp 入门

    UWP是什么我在这里就不说,本文主要是介绍如何入门UWP,也是合并我写的博客. 关于UWP介绍可以参见:http://lib.csdn.net/article/csharp/32451 首先需要申请一 ...

  8. JDBC基本开发

    JDBC基本开发步骤 一:注册驱动 方式一:DriverManager.registerDriver(new Driver()); //存在注册两次问题,性能较低,消耗资源 方式二:Class.for ...

  9. Windows Server 2008通过计划任务定时执行bat文件

    前段时间在Windows Server 2008安装了一套基于MySQL数据库的软件,处于数据安全的考虑,希望每天能够自动进行数据库备份.我在别人脚本的基础上自己写了一个数据库备份的bat脚本,双击该 ...

  10. Akka(32): Http:High-Level-Api,Route exception handling

    Akka-http routing DSL在Route运算中抛出的异常是由内向外浮出的:当内层Route未能捕获异常时,外一层Route会接着尝试捕捉,依次向外扩展.Akka-http提供了Excep ...