元数据,就是C#中封装的一些类,无法修改.类成员的特性被称为元数据中的注释.
1、什么是特性
1)属性与特性的区别
属性(Property):属性是面向对象思想里所说的封装在类里面的数据字段,Get,Set方法。
特性(Attribute): 官方解释:特性是给指定的某一声明的一则附加的声明性信息。 允许类似关键字的描述声明。它对程序中的元素进行标注,如类型、字段、方法、属性等。从.net角度看,特性是一种 类,这些类继承于System.Attribute类,用于对类、属性、方法、事件等进行描述,主要用在反射中。但从面向对象的级别看,其实Attribute是类型级别的,而不是对象级别。
Attributes和.net文件的元素据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响程序的行为。
2、特性的应用
(1).net中特性用来处理多种问题,比如序列化、程序的安全特性、防止即时编译器对程序代码进行优化从而代码容易调试等等。
定植特性的本质上是一个类的元素上去添加附加信息,并在运行其通过反射得到该附加信息(在使用数据实体对象时经常用到)
(2)Attribute 作为编译器的指令时的应用
Conditional:起条件编译的作用,只有满足条件,才允许编译器对它的代码进行编译。一般在程序调试的时候使用
DllImport: 用来标记费.net的函数,表明该方法在一个外部的DLL中定义。
Obsolete: 这个属性用来标记当前的方法已经废弃,不再使用
注:Attribute是一个类,因此DllImport也是一个类,Attribute类是在编译的时候实例化,而不是像通常那样在运行时实例化。
CLSCompliant: 保证整个程序集代码遵守CLS,否则编译将报错。
3、自定义特性
使用AttributeUsage,来控制如何应用新定义的特性
[AttributeUsageAttribute(AttributeTargets.All 可以应用到任何元素
,AllowMultiple=true, 允许应用多次,我们的定值特性能否被重复放在同一个程序实体前多次。
,Inherited=false,不继承到派生
)]
特性也是一个类,必须继承于System.Attribute类,命名规范为“类名”+Attribute。不管是直接还是间接继承,都会成为一个特性类,特性类的声明定义了一种可以放置在声明之上新的特性。
public class MyselfAttribute:System.Attribute
自定义特定:
- //限定特性类的应用范围
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field, AllowMultiple = true, Inherited = false)]
- //定制MsgAttribute特性类,继承于Attribute
- public class ClassMsgAttribute : Attribute
- {
- //定义_msg字段和Msg属性//Msg属性用于读写msg字段
- string _msg;
- public string Msg { get { return _msg; } set { _msg = value; } }
- public ClassMsgAttribute() { }
- //重载构造函数接收一个参数,赋值给_msg字段
- public ClassMsgAttribute(string s) { _msg = s; }
- }
//限定特性类的应用范围
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field, AllowMultiple = true, Inherited = false)]
//定制MsgAttribute特性类,继承于Attribute
public class ClassMsgAttribute : Attribute
{
//定义_msg字段和Msg属性//Msg属性用于读写msg字段
string _msg;
public string Msg { get { return _msg; } set { _msg = value; } }
public ClassMsgAttribute() { }
//重载构造函数接收一个参数,赋值给_msg字段
public ClassMsgAttribute(string s) { _msg = s; }
}
调用:
- //在Person类上标记ClassMsg特性
- [ClassMsg(Msg = "这是关于人的姓名信息的类")]
- class Person
- {
- //在_name字段上应用ClassMsg特性
- [ClassMsg("这是存储姓名的字段")]
- string _name;
- //以下特性无法应用,因为MsgAttribute定义的特性只能用于类和字段
- //[ClassMsg("这是读写姓名字段的属性")]
- public string Name { get { return _name; } set { _name = value; } }
- }
//在Person类上标记ClassMsg特性
[ClassMsg(Msg = "这是关于人的姓名信息的类")]
class Person
{
//在_name字段上应用ClassMsg特性
[ClassMsg("这是存储姓名的字段")]
string _name;
//以下特性无法应用,因为MsgAttribute定义的特性只能用于类和字段
//[ClassMsg("这是读写姓名字段的属性")]
public string Name { get { return _name; } set { _name = value; } }
}
主函数的情况
- static void Main(string[] args)
- {
- //获取Person类的Type对象tp
- Type tp = Type.GetType("Person");
- //获取tp对象的特性数组,并将数组赋值给MyAtts
- object[] MyAtts = tp.GetCustomAttributes(false);
- //遍历并输出MyAtts数组子项的Msg属性
- foreach (ClassMsgAttribute m in MyAtts)
- {
- Console.WriteLine("Person类的特性:{0}", m.Msg);
- }
static void Main(string[] args)
{
//获取Person类的Type对象tp
Type tp = Type.GetType("Person");
//获取tp对象的特性数组,并将数组赋值给MyAtts
object[] MyAtts = tp.GetCustomAttributes(false);
//遍历并输出MyAtts数组子项的Msg属性
foreach (ClassMsgAttribute m in MyAtts)
{
Console.WriteLine("Person类的特性:{0}", m.Msg);
}
GetCustomAttributes用于获取程序集的特性,也就是这个程序集合中包含了多少个特性
继续来一个简单的例子来说明定制特性:
using System;
public class HelpAttribute: Attribute //定制特性相当于一个类
{
//...
}
不管你是否相信,我们上面已经建立了一个定制特性,现在我们可以用它来装饰现有的类就好像我们使用的Obsolete attribute一样。
[Help()]
public class AnyClass
{
//...
}
注意:对于一个特性类使用Attribute后缀是一个惯例。然而,如果不添加编译器会自动添加匹配。
定义或控制特性的使用
AttributeUsage类是另外一个预定义特性类,它帮助我们控制我们自己的定制特性的使用。它描述一个定制特性如何被使用。
下面通过实例来探讨下AttributeUsage的三个属性
1)我们将会在刚才的Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。
- using System;
- [AttributeUsage(AttributeTargets.Class), AllowMultiple = false,
- Inherited = false ]
- public class HelpAttribute : Attribute
- {
- public HelpAttribute(String Description_in)
- {
- this.description = Description_in;
- }
- protected String description;
- public String Description
- {
- get
- {
- return this.description;
- }
- }
- }
using System;
[AttributeUsage(AttributeTargets.Class), AllowMultiple = false,
Inherited = false ]
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;
}
}
}
先让我们来看一下AttributeTargets.Class。它规定了Help特性只能被放在class的前面。这也就意味着下面的代码将会产生错误:
- [Help("this is a do-nothing class")]
- public class AnyClass
- {
- [Help("this is a do-nothing method")] //error
- public void AnyMethod()
- {
- }
- }
- //编译器报告错误如下:
- AnyClass.cs: Attribute 'Help' is not valid on this declaration type.
- It is valid on 'class' declarations only.
[Help("this is a do-nothing class")]
public class AnyClass
{
[Help("this is a do-nothing method")] //error
public void AnyMethod()
{
}
}
//编译器报告错误如下:
AnyClass.cs: Attribute 'Help' is not valid on this declaration type.
It is valid on 'class' declarations only.
我们可以使用AttributeTargets.All来允许Help特性被放置在任何程序实体前。可能的值是:
Assembly,
Module,
Class,
Struct,
Enum,
Constructor,
Method,
Property,
Field,
Event,
Interface,
Parameter,
Delegate,
All = Assembly Module Class Struct Enum Constructor Method Property Field Event Interface Parameter Delegate,
ClassMembers = Class Struct Enum Constructor Method Property Field Event Delegate Interface )
下面考虑一下AllowMultiple = false。它规定了特性不能被重复放置多次。
- [Help("this is a do-nothing class")]
- [Help("it contains a do-nothing method")]
- public class AnyClass
- {
- [Help("this is a do-nothing method")] //error
- public void AnyMethod()
- {
- }
- }
- 它产生了一个编译期错误。
- AnyClass.cs: Duplicate 'Help' attribute
[Help("this is a do-nothing class")]
[Help("it contains a do-nothing method")]
public class AnyClass
{
[Help("this is a do-nothing method")] //error
public void AnyMethod()
{
}
}
它产生了一个编译期错误。
AnyClass.cs: Duplicate 'Help' attribute
Ok,现在我们来讨论一下最后的这个属性。Inherited, 表明当特性被放置在一个基类上时,它能否被派生类所继承。
- [Help("BaseClass")]
- public class Base
- {
- }
- public class Derive : Base
- {
- }
- 这里会有四种可能的组合:
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]
[Help("BaseClass")]
public class Base
{
}
public class Derive : Base
{
}
这里会有四种可能的组合:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]
第一种情况:
如果我们查询(Query)(稍后我们会看到如何在运行期查询一个类的特性)Derive类,我们将会发现Help特性并不存在,因为inherited属性被设置为false。
第二种情况:
和第一种情况相同,因为inherited也被设置为false。
第三种情况:
为了解释第三种和第四种情况,我们先来给派生类添加点代码:
[Help("BaseClass")]
public class Base
{
}
[Help("DeriveClass")]
public class Derive : Base
{
}
现在我们来查询一下Help特性,我们只能得到派生类的属性,因为inherited被设置为true,但是AllowMultiple却被设置为false。因此基类的Help特性被派生类Help特性覆盖了。
第四种情况:
在这里,我们将会发现派生类既有基类的Help特性,也有自己的Help特性,因为AllowMultiple被设置为true。
C#特性学习笔记一的更多相关文章
-
java8 新特性学习笔记
Java8新特性 学习笔记 1主要内容 Lambda 表达式 函数式接口 方法引用与构造器引用 Stream API 接口中的默认方法与静态方法 新时间日期 API 其他新特性 2 简洁 速度更快 修 ...
-
C#特性学习笔记二
实例探讨: 自定义了一个特性类: [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)] class WahAttribute ...
-
InnoDB关键特性学习笔记
插入缓存 Insert Buffer Insert Buffer是InnoDB存储引擎关键特性中最令人激动与兴奋的一个功能.不过这个名字可能会让人认为插入缓冲是缓冲池中的一个组成部分.其实不然,Inn ...
-
C# 特性学习笔记
1.自己定义的特性 注意注释!!!!! 2.使用特性 3.特性的用处
-
Python高级特性学习笔记
切片(slice) 可简化循环取元素的操作. L[0:3] or L[:3] 表示从索引0的位置开始,到索引3为止,但不包括索引3的前3个元素(L[0],L[1],L[2]); L[-2:]表示取包括 ...
-
java8新特性学习笔记链接
https://blog.csdn.net/yitian_66/article/details/81010434
-
html5新特性学习笔记
1.语义化标签兼容问题(语义化标签只支持ie8以上,不包括ie8) 解决方法一:该标签的css中加上display:block; 通过DOM的方式创建这个标签 document.createEleme ...
-
Java8新特性学习笔记(一) Lambda表达式
没有用Lambda表达式的写法: Comparator<Transaction> byYear = new Comparator<Transaction>() { @Overr ...
-
Go类型特性-学习笔记
1.组合 Go语言使用组合来完成类型的设计,设计某一类型时想要拥有其他类型的功能只需要将其他类型嵌入该类型即可. 2.接口 与其他语言不同的是,编译器会自动判断该类型是否符合某正在使用的接口,甚至不需 ...
随机推荐
-
[MFC] MFC 查找其他窗口句柄 操作其他窗口
请直接查找CWnd类!!! CWnd* cWnd; cWnd= cWnd->FindWindowW(L"kwmusicmaindlg",NULL); CRect cRect; ...
-
$_session (应用)
登录: 封装类(用于连接数据库)代码中创建一个对象最好可以重复使用 <?php class DBDA { public $host="localhost"; public $ ...
-
GCD信号量并发控制
/** * 当我们在处理一系列线程的时候,当数量达到一定量,在以前我们可能会选择使用NSOperationQueue来处理并发控制,但如何在GCD中快速的控制并发呢?答案就是dispatch_sem ...
-
poj1088 经典DP
滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 88296 Accepted: 33100 Description ...
-
spring boot 常见的配置问题
最近在自学spring boot ,新手教程网上很多,这里主要记录下配置过程中的一些疑难杂症.这些记录都是针对以下配置生成的项目 1.该项目一定要用jdk1.8 2.application.prope ...
-
CentOS7 安装oracle客户端
1.本机环境CentOS7 64 [root@localhost etc]# uname -a Linux localhost.localdomain 3.10.0-693.el7.x86_64 #1 ...
-
excel 2007 无法输入中文
解决方法: 1.32位系统:找到C:\Program Files\Common Files\Microsoft Shared\OFFICE12\Office Setup Controller,将这个文 ...
-
BATJ面试必会之并发篇
一.线程状态转换 新建(New) 可运行(Runnable) 阻塞(Blocking) 无限期等待(Waiting) 限期等待(Timed Waiting) 死亡(Terminated) 二.使用线程 ...
-
如何判断CapsLock键是否按下
SHORT cap_state = ::GetKeyState(VK_CAPITAL); char str[10]; sprintf(str, "%d", ...
-
html5标签video(播放器)学习笔记(二)-基本操作
html5标签video(播放器)学习笔记(二)-基本操作 subying 发布时间: 2014/12/01 23:59 阅读: 13008 收藏: 21 点赞: 3 评论: 0 摘要 本文介绍了ht ...