C# Attribute 特性 学习
- 公共语言运行库允许您添加类似关键字的描述性声明(称为特性 (Attribute))来批注编程元素,如类型、字段、方法和属性 (Property)。属性与 Microsoft .NET Framework 文件的元数据一起保存,并且可用于向运行库描述代码或影响应用程序的运行时行为。
- 特性是一个对象,它可以加载到程序集及程序集的对象中,这些对象包括 程序集本身、模块、类、接口、结构、构造函数、方法、方法参,方法的返回值等,加载了特性的对象称作特性的目标。特性是为程序添加元数据(描述数据的数据)的一种机制,通过它可以给编译器提供指示或者提供对数据的说明。
- 为运行库编译代码时,该代码被转换为 Microsoft 中间语言 (MSIL),并同编译器生成的元数据一起被放到可移植可执行 (PE) 文件的内部。属性 (Attribute) 使您得以向元数据中放置额外的描述性信息,并可使用运行库反射服务提取该信息。
- 特性是一个对象,它是一个直接或间接继承System.Attribute的类的对象,只是特性类的实例化和应用方式有点特别,下面会详细说来!
- 通过从 .NET Framework 导入属性的命名空间来定义新的属性或使用现有属性。 例如:
[Obsolete("请使用新的SendMsg(Message msg)重载方法")]
public static void ShowMsg() {
Console.WriteLine("这是旧的SendMsg()方法");
}
Obsolete特性是一个系统特性,标记不再使用的程序元素。 - 通过在紧邻代码元素之前放置属性来将该属性应用于代码元素。 特性的使用方法:首先是有一对方括号“[]”,在左方括号“[”后紧跟特性的名称,比如Obsolete,随后是一个圆括号“()”。 和普通的类不同,这个圆括号不光可以写入构造函数的参数,还可以给类的属性赋值,在Obsolete的例子中,仅传递了构造函数参数。 当特性应用与程序集和模块时,C#允许以指定的前缀来表示特性所应用的目标元素,建议这样来处理,因为显式处理可以消除可能带来的二义性。 例如:
namespace Anytao.net {
[assembly: MyAttribute()] //应用于程序集
[moduel: MyAttribute()] //应用于模块
pubic class Attribute_how2do { //略 }
} - 为属性指定位置参数和命名参数。
位置参数:构造函数的参数。 命名参数:属性作为参数。 使用构造函数参数,参数的顺序必须同构造函数声明时的顺序相同,所有在特性中也叫位置参数(Positional Parameters),与此相应,属性参数也叫做命名参数(Named Parameters)。位置参数是必需的,并且必须放在所有命名参数之前;
- 创建自定义类,类名以Attribute结尾(所有特性类都是以Attribute结尾,这是约定俗成的,这样符合微软的命名风格,也符合编译器的搜索规则,但不是必须的),间接或者直接继承System.Attribute类。
- 在我们的特性类上应用AttributeUsage系统特性,用于指定我们的自定义特性的应用目标类型。AttributeUsage特性的位置参数有一个是AttributeTargets枚举位标记类型的,通过它来指定我们的自定义特性的应用目标。另外还有两个命名参数 AllowMultiple 是否可以将特性重复应用到目标上;Inherited 咱们自定义的特性类是否可以被继承。
- 声明类属性,用于存储我们要添加的元数据。通过构造函数赋值的属性,设为只读(只有get访问器),其它则为读写属性。这里这样做的目的是,在特性使用的时候,构造函数参数也就是位置参数是必需提供的,而命名参数,也就是为读写属性赋值是可选的,你将如果将位置参数设为读写属性,那它也将出现在命名参数中。
- 声明构造函数,为只读属性赋值。当然你也可以在里面声明一些方法,只是方法在应用特性的时候没法体现。也可以像普通自定义类一样,调用类的方法。
namespace Common.Library.ChangeRecord
{
/// <summary>
/// desc:记录 修改记录 的特性
/// </summary>
[AttributeUsage((AttributeTargets), AllowMultiple = true, Inherited = false)]
public class RecordAttribute : Attribute
{
private RecordType recordType; // 记录类型:更新/创建
private string author; // 作者
private DateTime date; // 更新/创建 日期
private string mark; // 备注 // 构造函数,构造函数的参数在特性中也称为“位置参数”。
public RecordAttribute(RecordType recordType, string author, string date)
{
this.recordType = recordType;
this.author = author;
this.date = Convert.ToDateTime(date);
} // 对于位置参数,通常只提供get访问器
public RecordType RecordType { get { return recordType; } }
public string Author { get { return author; } }
public DateTime Date { get { return date; } } // 构建一个属性,在特性中也叫“命名参数”
public string Mark
{
get { return mark; }
set { mark = value; }
}
}
/// <summary>
/// 记录类型 枚举
/// </summary>
public enum RecordType
{
Add,
Modify
}
}
NOTE:注意构造函数的参数 date,必须为一个常量、Type类型、或者是常量数组,所以不能直接传递DateTime类型。
这个类看上去和普通的类没有和大区别,显然不能它因为名字后面跟了个Attribute就摇身一变成了特性。它满足了,我们前面所说的自定义特性的要求,继承了System.Attribute类、用AttributeUsage特性限制了应用的目标、有属性和构造函数等。
下面是应用特性:
namespace Common.Library
{
[Record(RecordType.Add, "Joey", "2013-07-23")]
[Record(RecordType.Modify, "Joey", "2013-07-23", Mark = "测试")]
[Record(RecordType.Modify, "Joey", "2013-07-24", Mark = "修改bug")]
public class TestAttribute
{
[Record(RecordType.Add, "Joey", "2013-07-23", Mark = "测试特性附加到方法上")]
[Record(RecordType.Add, "Shovy", "2013-07-25", Mark = "修改此方法")]
public void MyMethod()
{
} [Record(RecordType.Add, "Joey", "2013-07-23", Mark = "方法2")]
[Record(RecordType.Add, "Zoe", "2013-07-25", Mark = "修改方法2")]
public void Method2()
{
}
}
}

- protected Attribute(): 保护的构造器,只能被Attribute的派生类调用。
- 三个静态方法: static Attribute GetCustomAttribute():这个方法有8种重载的版本,它被用来取出施加在类成员上指定类型的Attribute。 static Attribute[] GetCustomAttributes(): 这个方法有16种重载版本,用来取出施加在类成员上指定类型的Attribute数组。 static bool IsDefined():由八种重载版本,看是否指定类型的定制attribute被施加到类的成员上面。
- 实例方法: bool IsDefaultAttribute(): 如果Attribute的值是默认的值,那么返回true。 bool Match():表明这个Attribute实例是否等于一个指定的对象。
- 公共属性: TypeId: 得到一个唯一的标识,这个标识被用来区分同一个Attribute的不同实例。 我们简单地介绍了Attribute类的方法和属性,还有一些是从object继承来的。这里就不列出来了。
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
TestAttribute testClass = new TestAttribute();
Type type = testClass.GetType(); //获取要获得自定义特性的类型的Type对象
Attribute[] myAttributes = Attribute.GetCustomAttributes(type);//获取类型上添加的自定义特性
Console.WriteLine("类型{0}上应用的Record特性:", type.ToString());
Console.WriteLine();
foreach (Attribute item in myAttributes)
{
if (item.GetType() == typeof(RecordAttribute)) //只打印咱自定义的特性
{
RecordAttribute attr = (RecordAttribute)item;
Console.WriteLine(" 类型:{0},更改人:{1},更改时间:{2},备注:{3}", attr.RecordType, attr.Author, attr.Date.ToString("yyyy-MM-dd"), attr.Mark);
}
}
Console.WriteLine();
Console.WriteLine("类型{0}的方法上应用的Record特性:", type.ToString());
Console.WriteLine();
foreach (MethodInfo mInfo in type.GetMethods()) //遍历该类型的所有方法
{
if (Attribute.IsDefined(mInfo, typeof(RecordAttribute))) //只有在方法上附加了属性,才遍历
{
Console.WriteLine(" 类型{0}的{1}方法上的Record特性", type.ToString(), mInfo.ToString());
Console.WriteLine();
foreach (Attribute item in Attribute.GetCustomAttributes(mInfo)) //遍历方法上的 特性
{
if (item.GetType() == typeof(RecordAttribute))
{
RecordAttribute attr = (RecordAttribute)item;
Console.WriteLine(" 类型:{0},更改人:{1},更改时间:{2},备注:{3}", attr.RecordType, attr.Author, attr.Date.ToString("yyyy-MM-dd"), attr.Mark);
}
}
Console.WriteLine();
}
}
}
}}
运行效果如下图所示:
获取自定义特性的方法二:
首先基于类型(本例中是DemoClass)获取一个Type对象,然后调用Type对象的GetCustomAttributes()方法,获取应用于该类型上的特性。
当指定GetCustomAttributes(Type attributeType, bool inherit) 中的第一个参数attributeType时,
将只返回指定类型的特性,否则将返回全部特性;第二个参数指定是否搜索该成员的继承链以查找这些属性。
代码如下:
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
TestAttribute testClass = new TestAttribute();
Type type = testClass.GetType();
object[] records = type.GetCustomAttributes(typeof(RecordAttribute), false); //获取类型上的特性
Console.WriteLine("类型{0}上应用的Record特性:", type.ToString());
Console.WriteLine();
foreach (RecordAttribute record in records)
{
Console.WriteLine(" 类型:{0},更改人:{1},更改时间:{2},备注:{3}", record.RecordType, record.Author, record.Date.ToString("yyyy-MM-dd"), record.Mark);
}
Console.WriteLine();
Console.WriteLine("类型{0}的方法上应用的Record特性:", type.ToString());
Console.WriteLine();
foreach (MethodInfo mInfo in type.GetMethods()) //遍历该类型的所有方法
{
if (Attribute.IsDefined(mInfo, typeof(RecordAttribute))) //只有在方法上附加了属性,才遍历
{
Console.WriteLine(" 类型{0}的{1}方法上的Record特性", type.ToString(), mInfo.ToString());
Console.WriteLine();
foreach (RecordAttribute record in mInfo.GetCustomAttributes(typeof(RecordAttribute), false)) //遍历方法上的 特性
{
Console.WriteLine(" 类型:{0},更改人:{1},更改时间:{2},备注:{3}", record.RecordType, record.Author, record.Date.ToString("yyyy-MM-dd"), record.Mark);
}
Console.WriteLine();
}
}
}
}
}
两种方法运行的结果是一样的,如上图。这两种方法的区别在与,第一种方法是用的Atrribute基类的静态方法获取对应类型的自定义特性的集合。而第二种方案是使用的Type类型的方法获取的。
demo下载:点击这里下载代码
资料:
http://www.cnblogs.com/JimmyZhang/archive/2008/01/27/1055254.html
Attribute在.net编程中的应用(一)
Attribute在.net编程中的应用(二)
Attribute在.net编程中的应用(三)
Attribute在.net编程中的应用(四)
Attribute在.net编程中的应用(五)
C# Attribute 特性 学习的更多相关文章
- .net学习之Attribute特性和EF关键知识点
一.Attribute特性/标签1.Attribute用来对类.属性.方法等标注额外的信息,贴一个标签简单的说,定制特性Attribute,本质上就是一个类,它为目标元素提供关联附加信息,并在运行时以 ...
- [C#]Attribute特性(2)——方法的特性及特性参数
上篇博文[C#]Attribute特性介绍了特性的定义,类的特性,字段的特性,这篇博文将介绍方法的特性及特性参数相关概念. 3.方法的特性 之所以将这部分单列出来进行讨论,是因为对方法的特性查询的反射 ...
- Net中Attribute特性的高级使用及自定义验证实现
好久没写博客了,今天在百忙之中抽空来写篇文章,记录一下最近深入学习Attribute特性的笔记及心得.~~ 一.什么是特性? 特性(Attribute)是用于在运行时传递程序中各种元素(比如类.方法. ...
- [C#]Attribute特性(3)——AttributeUsage特性和特性标识符
相关文章 [C#]Attribute特性 [C#]Attribute特性(2)——方法的特性及特性参数 AttributeUsage特性 除了可以定制自己的特性来注释常用的C#类型外,您可以用At ...
- 关于C# 中的Attribute 特性
关于C# 中的Attribute 特性 作者: 钢钢 来源: 博客园 发布时间: 2011-01-09 23:30 阅读: 13921 次 推荐: 12 原文链接 [收藏] 摘要:纠结地说 ...
- Attribute特性验证模型model
数据验证我们往往分为前台验证和后台验证,而我们的后台验证每到一个方法中就要去验证一次,这样的代码想想都难以维护,这篇我们这篇文章就是为了解决这样的问题.用attribute 这个特性来解决这样的问题 ...
- 如何在方法上贴上attribute(特性)捕捉方法的异常,来实现我们的需求
在方法上贴上attribute(特性)捕捉方法的异常,其实这么做也是为了在项目中不会大量使用try-cacth这样的语句,同时使我们的代码看起来更简洁,更直观,将逻辑业务分离使得后期维护方便.这里我们 ...
- .NET进阶篇03-Reflection反射、Attribute特性
知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 内容目录 一.概述二.反射1.反射使用2.创建对象3.调用方法4.字段属性三.特性四.总结 一.概述 反射其实无处不在,我们用VS进行调试时候, ...
- Java8 新特性学习 Lambda表达式 和 Stream 用法案例
Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...
随机推荐
- C语言 百炼成钢3
//题目7:用*号输出空心菱形图案 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> # ...
- U3D临时文件GICache巨大
C:\Users\asus\AppData\LocalLow\Unity\Caches\GiCache 看名字似乎是全局光的缓存,可以通过Edit - Preference - GI Cache,选中 ...
- Unity架构有点乱
1,没有合理的将公共的东西归入到基类中,而是分散到子类中,有许多重复. 比如 enbled的变量本应该是所有component所共有的一个属性,应该写在component.然而却发现并非这样,enbl ...
- js 中的算法题,那些经常看到的
js中遇到的算法题不是很多,可以说基本遇不到.但面试的时候,尤其是一些大公司,总是会出这样那样的算法题,考察一个程序员的逻辑思维能力.如下: 1.回文. 回文是指把相同的词汇或句子,在下文中调换位置或 ...
- 修改 dispatchTouchEvent方法 来处理事件冲突
PagerIndicator把事件给拦截了 我修改了他的 dispatchTouchEvent方法 请求他爹和他祖宗不要拦截我的事件 根据事件分发机制 dispatchTouchEvent-> ...
- Jsoup开发简单网站客户端之读取本地html文件
用jsoup解析网页,相比于那些返回api数据来说 肯定耗流量,加载慢,所以程序assts中预先放了一个最新的html文件,第一次进来不走网络,直接从本地取,以后会加上wifi离线功能. 首先离线网站 ...
- Java系列:《Java核心技术 卷一》学习笔记,chapter11 记录日志
11.5 日志记录 可以通过Loger.getGlobal().info(xxxx);的方式来记录log. 11.5.2 高级日志 1)通过一个包名来 创建一个新的日志记录器. private sta ...
- 20145215《Java程序设计》第3周学习总结
20145215<Java程序设计>第三周学习总结 教材学习内容总结 认识对象 类类型 在学习第三章的时候,我们知道Java可区分为基本类型和类类型两大类型系统,其中类类型也称为参考类型. ...
- ROM存储1/4周期正弦信号构造DDS
上周的时候,老师让编写一个简单的dds程序,本文说明了整个过程中我遇到问题以及一些个人的思考.初次接触FPGA,如有问题请多多指教~ 1.几个疑问,解决和没有解决的. 为何采用ROM而不是直接采用DD ...
- [转]细说MySQL Explain和Optimizer Trace简介
在开发过程中,对每个上线的SQL查询指纹(query figerprint)的质量都应有估算:而估算DB查询质量最直接的方法,就是分析其查询执行计划( Query Execution Plan ,即Q ...