18.1 使用定制特性

  • FCL 中的几个常用定制特性.

    • DllImport 特性应用于方法,告诉 CLR 该方法的实现位于指定 DLL 的非托管代码中.
    • Serializable 特性应用于类型,告诉序列化格式化器一个实例的字段可以序列化和反序列化.
    • AssemblyVersion 特性应用于程序集,设置程序集的版本号.
    • Flags特性应用于枚举类型,枚举类型就成了位标志集合.
  • C# 允许用一个前缀明确指定特性要应用于的目标元素.有时可省略,编译器能推断;有时则必须指定前缀.

using System;

[assembly: SomeAttr]                    //应用于程序集
[module: SomeAttr] //应用于模块 [type: SomeAttr] //应用于类型
internal sealed class SomeType<[typevar: SomeAttr] T> //应用于泛型类型变量
{
[field: SomeAttr] //应用于字段
public int SomeField = 0; [return: SomeAttr] //应用于返回值
[method: SomeAttr] //应用于方法
public int SomeMethod(
[param: SomeAttr] //应用于参数
int someParam) { return someParam; } [property: SomeAttr] //应用于属性
public string SomeProp {
[method: SomeAttr] //应用于get访问器方法
get { return null; }
} [event: SomeAttr] //应用于事件
[field: SomeAttr] //应用于编译器生成的字段
[method: SomeAttr] //应用于编译器生成的add & remove方法
public event EventHandler SomeEvent;
}
  • CLS 要求定制特性类必须直接或间接从公共抽象类 System.Attribute 派生.
  • 应用特性时,c# 编译器允许省略 Attribute 后缀以减少打字量,并提升源代码的可读性.
  • 特性是类的实例,语法类似于调用类的某个实例构造器.如:
    [DllImport("Kernel32", CharSet = CharSet.Auto, SetLastError = true)]
  • "Kernel32" 是构造器的参数,称为定位参数,必须指定.
  • CharSetSetLastError 用于设置字段或属性,称为命名参数,是可选的.
  • 在C#中,既可将每个特性都封闭到一对方括号中,也可在一对方括号中封闭多个以逗号分隔的特性.如果特性类的构造器不获取参数,那么圆括号也可以省略,如:
    • [Serializable][Flags]
    • [Serializable,Flags]
    • [FlagsAttribute,SerializableAttribute]
    • [FlagsAttribute(), SerializableAttribute()]

18.2 定义自己的特性类

    1. Attribute 继承; 2) 类名有 Attribute 后缀(非必须).
  • AttributeUsage 特性是一个简单的类,可利用它告诉编译器定制特性的合法应用范围.所有编译器都内建了对该特性的支持.如:
    [AttributeUsage(AttributeTargets.Enum, Inherited = false)]
public class FlagsAttribute : Attribute
{
public FlagsAttribute() { }
}
  • AttributeUsageAttribute 类有一个公共构造器,它允许传递位标志来指明特性的合法应用范围.
  • AttributeUsageAttribute 类有两个公共属性.其中 AllowMultiple 指示是否允许将该特性多次应用于同一个目标元素; Inherited 指出特性在应用于基类时,是否同时应用于派生类和重写的方法.
  • 如果忘记向自己的特性类应用 AttributeUsageAttribute 特性,则特性类默认为应用于所有目标元素,向每个目标元素都只能应用一次,而且可继承.

18.3 特性构造器和字段/属性数据类型

  • 定义特性类的实例构造器\字段和属性时,只允许Boolean,Char,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,Single,Double,String,Type,Object 或枚举类型.
  • 应用特性时必须传递一个编译时常量表达式,它与特性类定义的类型匹配.
  • 定制特性: 它是类的实例,被序列化成驻留在元数据中的字节流.远行时可对元数据中的字节进行反序列化,从而构造出类的实例.

18.4 检测定制特性

  • 有三个方法可以获取与目标关联的特性: IsDefined,GetCustomAttributesGetCustomAttribute
  • IsDefined 比另外两个方法更高效,因为 IsDefined 不会构造特性对象,不会调用构造器,也不会设置字段和属性.

18.5 两个特性实例的相互匹配

  • System.Attribute 重写了 ObjectEquals 方法,利用反射来比较两个特性对象中的字段值(为每个字段都调用 Equals).所有字段都匹配就返回 true ; 否则返回 false.建议重写 Equals 来移除反射的使用.
  • System.Attribute 还公开了虚方法 Match ,其默认实现只是调用 Equals 方法并返回它的结果.

18.6 检测定制特性时不创建从Attribute派生的对象

18.7 条件特性类

<NET CLR via c# 第4版>笔记 第18章 定制特性的更多相关文章

  1. <NET CLR via c# 第4版>笔记 第19章 可空值类型

    System.Nullable<T> 是结构. 19.1 C# 对可空值类型的支持 C# 允许用问号表示法来声明可空值类型,如: Int32? x = 5; Int32? y = null ...

  2. <NET CLR via c# 第4版>笔记 第17章 委托

    17.1 初识委托 .net 通过委托来提供回调函数机制. 委托确保回调方法是类型安全的. 委托允许顺序调用多个方法. 17.2 用委托回调静态方法 将方法绑定到委托时,C# 和 CLR 都允许引用类 ...

  3. <NET CLR via c# 第4版>笔记 第16章 数组

    //创建一个一维数组 int[] myIntegers; //声明一个数组引用 myIntegers = new int[100]; //创建含有100个int的数组 //创建一个二维数组 doubl ...

  4. <NET CLR via c# 第4版>笔记 第13章 接口

    13.1 类和接口继承 13.2 定义接口 C#用 interface 关键字定义接口.接口中可定义方法,事件,无参属性和有参属性(C#的索引器),但不能定义任何构造器方法,也不能定义任何实例字段. ...

  5. <NET CLR via c# 第4版>笔记 第12章 泛型

    泛型优势: 源代码保护 使用泛型算法的开发人员不需要访问算法的源代码.(使用c++模板的泛型技术,算法的源代码必须提供给使用算法的用户) 类型安全 向List<DateTime>实例添加一 ...

  6. <NET CLR via c# 第4版>笔记 第5章 基元类型、引用类型和值类型

    5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...

  7. <NET CLR via c# 第4版>笔记 第6章 类型和成员基础

    6.1 类型的各种成员 6.2 类型的可见性 public 全部可见 internal 程序集内可见(如忽略,默认为internal) 可通过设定友元程序集,允许其它程序集访问该程序集中的所有inte ...

  8. <NET CLR via c# 第4版>笔记 第7章 常量和字段

    7.1 常量 常量 是值从不变化的符号.定义常量符号时,它的值必须能够在编译时确定. 只能定义编译器识别的基元类型的常量,如果是非基元类型,需把值设为null. 常量的值直接嵌入代码,所以不能获取常量 ...

  9. <NET CLR via c# 第4版>笔记 第8章 方法

    8.1 实例构造器和类(引用类型) 构造引用类型的对象时,在调用类型的实例构造器之前,为对象分配的内存总是先被归零 .没有被构造器显式重写的所有字段都保证获得 0 或 null 值. 构造器不能被继承 ...

随机推荐

  1. [BZOJ1196][HNOI2006]公路修建问题 二分答案+最小生成树

    Description OI island是一个非常漂亮的岛屿,自开发以来,到这儿来旅游的人很多.然而,由于该岛屿刚刚开发不久,所以那 里的交通情况还是很糟糕.所以,OIER Association组 ...

  2. [shiro] - 怎样使用shiro?

    shiro是什么? Shiro是apache旗下的一个开源框架, 它将软件系统的安全认证相关的功能抽取出来, 实现用户身份认证, 权限授权, 加密, 会话管理等功能, 组成一个通用的安全认证框架. 为 ...

  3. [Err] 1111 - Invalid use of group function

    本文为博主原创,未经允许不得转载: 初衷,本想通过group by sql语句查询出不同id下总数在一定范围内的数据,所以产生如下的sql,及错误sql AND STATDATE < ' GRO ...

  4. UVa 1025 城市里的间谍

    https://vjudge.net/problem/UVA-1025 题意:一个间谍要从第一个车站到第n个车站去会见另一个,在是期间有n个车站,有来回的车站,让你在时间T内时到达n,并且等车时间最短 ...

  5. 关于Java 中Integer 和Long对象 对比的陷阱(简单却容易犯的错误)

    彩票客户端“忘记密码”功能有bug,今天调试时,发现了原因: 功能模块中有一段: if(userpo.getId()!=Long.valueOf(uid)){ throw new VerifyExce ...

  6. Spring boot 遇到了连接mysql的错误

    问题1: Establishing SSL connection without server's identity verification is not recommended. Accordin ...

  7. [原][JSBSim]基于qt代码实现:TCP|UDP与飞行模拟软件JSBSim的通信,现实模型飞行!

    废话没有,上关键代码 头文件 #include <QUdpSocket> #include <qtcpsocket.h> #ifndef vrUDP #define vrUDP ...

  8. export与export default exports与module.exports的用法

    转载:http://blog.csdn.net/zhou_xiao_cheng/article/details/52759632 本文原创地址链接:http://blog.csdn.net/zhou_ ...

  9. Java基础十--接口

    Java基础十--接口 一.接口的定义和实例 /* abstract class AbsDemo { abstract void show1(); abstract void show2(); } 8 ...

  10. English trip -- VC(情景课)1 B Countries

    Vocabulary focus 核心词汇 Vo ca bu la ry   fo cus [və(ʊ)'kæbjʊlərɪ]      ['fəʊkəs] Listen and repeat  听并 ...