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. Python time strptime()与time strftime()

    time strftime()接收时间元组,返回表示时间的字符串. time strptime()把时间字符串,解析成一个时间元组. import time t = time.strftime('%Y ...

  2. Python的collections模块中的OrderedDict有序字典

    如同这个数据结构的名称所说的那样,它记录了每个键值对添加的顺序. ? 1 2 3 4 5 6 d = OrderedDict() d['a'] = 1 d['b'] = 10 d['c'] = 8 f ...

  3. package 'orocos-bfl' not found CMake Error at /usr/share/cmake-2.8/Modules/FindPkgConfig.cmake:283 (message):

    #没有数字 sudo apt-get install ros-indigo-bfl

  4. shell 特殊变量详解

    $0 获取当前执行脚本的名称,包括路径 [root@centos test]# cat test.sh echo $0 [root@VM_102_244_centos test]# bash test ...

  5. 《剑指offer》第三十三题(二叉搜索树的后序遍历序列)

    // 面试题33:二叉搜索树的后序遍历序列 // 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果. // 如果是则返回true,否则返回false.假设输入的数组的任意两个数字都 ...

  6. 《剑指offer》第九题(用两个栈实现队列)

    // 面试题:用两个栈实现队列 // 题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail // 和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的 ...

  7. 《剑指offer》第三_一题(找出数组中重复的数字,可改变数组)

    // 面试题3(一):找出数组中重复的数字 // 题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内.数组中某些数字是重复的,但不知道有几个数字重复了, // 也不知道每个数字重复了几次.请 ...

  8. js、jq对象互转

    1.js对象转jq对象:    $() $('#kw') $(document.getElementById("kw")) 2.jq对象转js对象: $(this).get(0) ...

  9. Idea设置默认不折叠一行的函数

  10. Python requests快速上手

    Python requests快速上手 这里参考官方文档,在ide中写了一遍,加深一下印象,定义的函数只是为了方便区分不同的请求方式 #-*-coding:utf-8-*- # Time:2017/1 ...