C#特性学习笔记一
元数据,就是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.接口 与其他语言不同的是,编译器会自动判断该类型是否符合某正在使用的接口,甚至不需 ...
随机推荐
- 浅谈AJAX的基本原理和原生AJAX的基础用法
一.什么是AJAX? AJAX,即"Asynchronous Javascript And XML",翻译为异步的JavaScript和XML,是一种创建交互式网页应用的网页开发技 ...
- JavaWeb基础: ServletContext
基本概念 Web容器在启动时,会为每个Web应用程序都创建一个对应的ServletContext对象,它代表当前Web应用. ServletContext(javax.servlet.http.Ser ...
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
- 转载-Web API 入门
An Introduction to ASP.NET Web API 目前感觉最好的Web API入门教程 HTTP状态码 Web API 强势入门指南 Install Mongodb Getting ...
- sphinx 源码阅读之分词,压缩索引,倒排——单词对应的文档ID列表本质和lucene无异 也是外部排序再压缩 解压的时候需要全部扫描doc_ids列表偏移量相加获得最终的文档ID
转自:http://github.tiankonguse.com/blog/2014/12/03/sphinx-token-inverted-sort.html 外部排序 现在我们的背景是有16个已经 ...
- ASP.NET中的Session怎么正确使用[转]
Session对象用于存储从一个用户开始访问某个特定的aspx的页面起,到用户离开为止,特定的用户会话所需要的信息.用户在应用程序的页面切换时,Session对象的变量不会被清除. 对于一个Web应用 ...
- web项目的日志打印位置设置
1, 若在项目中放logback.groovy文件(如: src/test/resource下),则日志会打印到控制台上. logback.groovy 内容如下: // // Built on Fr ...
- build.xml详解
build.xml详解1.<project>标签每个构建文件对应一个项目.<project>标签时构建文件的根标签.它可以有多个内在属性,就如代码中所示,其各个属性的含义分别如 ...
- Apache +Tomcat的负载均衡与集群配置
实验拓扑图: 一.搭配环境 (1).Tomcat的安装和配置 Tomcat_a的ip:192.168.55.229 Tomcat_b的ip:192.168.55.231 Tomcat的需要安装jdk和 ...
- Learning with Trees
We are now going to consider a rather different approach to machine learning, starting with one of t ...