C#锐利体验 第十五讲 特征

转载 2004年09月06日 01:03:00

第十五讲 特征

特征
特征(Attribute)是C#为组件编程引入的一个令人兴奋的创新,它使得我们可以为程序的各种元素如类,结构,接口,方法等提供额外的描述性信息。这些描述性信息在程序代码运行时又可以被我们提取利用。我们先来看一个示例程序:
using System;
public class AuthorAttribute: Attribute //作者特征类
{
    public AuthorAttribute(string name) { this.name = name; }
    public string Name { get { return name; }}
    private string name;
}

[Author("Anders Hejlsberg")]//特征实例化
class MyClass {
    int count;
    public MyClass(int count) { this.count=count; }
    public int Count { get { return count; }
    }
}

class Test {
    static void Main() {
        Type t1= typeof(MyClass);
        Type t2=typeof(AuthorAttribute);
        object[] arr = t1.GetCustomAttributes(t2, true);//获取特征实例(数组)
        Console.Write("The author of MyClass is :");
        foreach(object o in arr) {
            AuthorAttribute aa = (AuthorAttribute) o;
            Console.Write(" {0} ", aa.Name);
        }
        Console.WriteLine();
    }
}
程序首先声明并实现了一个AuthorAttribute特征类,特征类必须直接或间接继承自抽象类System.Attribute,这往往是我们在使用特征时的第一步。它将是我们提供描述性信息的数据结构。值得指出的是AuthorAttribut特征类名中的后缀“Attrubute”是C#推荐的特征类的命名方式,并非必须如此。
接下来在我们实现自己的类MyClass的时候,我们便采用前面的AuthorAttribute特征类来为MyClass提供描述信息。特征实例化语句[Author("Anders Hejlsberg")]帮助我们完成这一行为。这里的中括号“[ ]”告诉C#我们在进行特征实例化。Author是AuthorAttribute类的去掉后缀“Attrubute”的简写形式——C#编译器可以自动识别,当然我们将Author换成AuthorAttribute后效果是一样的。其中("Anders Hejlsberg")将调用AuthorAttribute特征类的AuthorAttribute(string name) 实例构造器。通过这样的特征实例化语句后,我们就给我们的MyClass类提供了一个“撰写者”(AuthorAttribute)的特征描述。在Test测试类中,我们便可以通过映射(下面的专题将予以详述)来获得我们先前设定的描述信息。运行程序可以得到下面的结果:The author of MyClass is : Anders Hejlsberg 。

参数
特征实例化时有两种参数,一种如我们上面的由特征类的实例构造器定义的参数,称为“位置参数”。另一种是由特征类中给定义的实例公有域或实例属性的赋值的参数,称为“指定参数”,看下面的特征类的实现:
public class HelpAttribute: Attribute {
    public HelpAttribute(string url) { this.url = url; }
    public string Topic = null;
    private string url;
    private int number=-1;
    public string Url { get { return url; }}
    public int Number {
        get { return number; }
        set { number=value; }
    }
}
对于这样一个特征类的实例化,我们往往采用下面的语句:[Help("http://www.ccw.com.cn",Topic="A demo class",Number=120)]。其中http://www.ccw.com.cn是位置参数。而Topic="A demo class"是指定参数,对应HelpAttribute类中的Topic公有域。Number=120也是指定参数,对应HelpAttribute类中的Number公有属性。
位置参数和相应的特征类的实例构造器紧密相关——构造器提供了什么样的参数构造方式,位置参数就对应什么样的形式。位置参数不可省略,当然如果特征类提供了无参数的构造器,那应该另当别论。指定参数对应着特征类的实例公有域或实例属性,它在实例化的时候并非必须,可以省略。
位置参数和指定参数对它们的类型也有要求,这主要是要能保证在中括号“[ ]”实例化语句中能完成各个参数的初始化。它们必须是下列类型之一:八种整数类型sbyte, short, int, long,byte, ushort, uint和ulong;字符类型char和布尔类型bool;两种浮点类型float 和double;System.Object(即object)和System.Type(typeof操作符返回值);枚举类型。

AttributeUsage特征类
AttributeUsage特征类是C#保留的三个特征类之一,其他两个是条件特征类ConditionalAttribute和废弃特征类ObsoleteAttribute。
AttributeUsage特征类用来描述我们的自己实现的特征类“怎样描述其他类”,比如我们实现的特征类用于描述方法,还是类,接口?另外是否允许我们的特征类对同一个编程元素进行多次描述(比如一个类的撰写者可能有多个)?一个类在被我们的特征类描述后,这种描述是否能够体现在他的继承子类上?AttributeUsage特征类通过三个属性来体现上述的行为:ValidOn,AllowMultiple,Inherited。下面是特征类的原型:
[AttributeUsage(AttributeTargets.Class)]
public class AttributeUsageAttribute: Attribute
{
    public AttributeUsageAttribute(AttributeTargets validOn) {...}
    public virtual bool AllowMultiple { get {...} set {...} }
    public virtual bool Inherited { get {...} set {...} }
    public virtual AttributeTargets ValidOn { get {...} }
}
其中AttributeTargets是一个枚举类型,可以指定各种描述目标。需要指出的是AttributeUsage特征类只能够用于直接或间接继承自System.Attribute的类,否则编译器会报错。
下面的例子演示了AttributeUsage特征类的典型用法:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AuthorAttribute: Attribute {
    public AuthorAttribute(string name) {
        this.name = name;
    }
    public string Name { get { return name; }}
    private string name;
}
其中指定了AuthorAttribute特征类只能用于描述类(AttributeTargets.Class),并且它允许用多个AuthorAttribute特征类来描述同一个编程元素(AllowMultiple = true)。这里并没有指定Inherited的值,它默认为真(true),也就是允许继承子类获得父类的描述。实际上对于一个没有用AuthorAttribute描述的特征类:
class X Attribute: Attribute{ ... }
它相当于
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
class X Attribute: Attribute{ ... }
被AttributeUsage描述的特征类,必须严格按照指定的描述信息去描述其他编程元素,否则会引起编译器报错!
条件特征类ConditionalAttribute定义在某些条件下才能够产生调用的类。废弃特征类ObsoleteAttribute顾名思义是指在某些情况下我们不推荐使用旧有的被废弃的类型或方法等编程元素,这时我们在他的前面加上废弃特征类从而可以通知编译器,编译器编译时往往会给出警告信息。

体验套餐管理系统

1.3/// //定义几个检查项目 CheckItem sg, tz, sl, tl, ggn, bc, xdt; //定义一个系统默认的检查套餐“入学体检” ...
  • wuji3390
  • wuji3390
  • 2017年05月08日 18:02
  • 434

迁移学习全面概述

深度 | 迁移学习全面概述:从基本概念到相关研究 2017-03-27 15:02无人驾驶/谷歌/操作系统 选自sebastianruder.com 作者:Sebastian R...
  • wmsbeijing
  • wmsbeijing
  • 2017年11月11日 16:06
  • 123

第十五讲(第二阶段)

今日结果:        1  C++ 是一种混合语言,结构化的面向对象的语言。全面的兼容C语言,可不加修饰的使用C代码。        2  bool 类型  // 只有ture 或 false...
  • yishengzhiai005
  • yishengzhiai005
  • 2014年05月16日 00:33
  • 262

第十五讲:重载

静态类             不依赖于对象,通常用作工具类             使用static关键字修饰                      特点:             它们仅包含静...
  • wljhk2006
  • wljhk2006
  • 2014年03月10日 13:41
  • 280

第十五周 体验复制文件

/* *程序的版权和版本声明部分: *Copyright(c)2013,烟台大学计算机学院学生 *All rights reserved. *文件名称: *作者:尚振伟 *完成日期:201...
  • u012369373
  • u012369373
  • 2014年06月02日 19:36
  • 474

Linux运维第十五讲

553 文件系统不允许 500 权限过大 530 权限过小 密码不对 服务不对   1.永久修改安全上下文 [root@ftpserver homes]# semanage fcontext...
  • qq_31813491
  • qq_31813491
  • 2017年03月01日 18:17
  • 59

第十五讲:SQLite入门指南

本讲内容:在Android中使用SQLite数据库的入门指南,打算分下面几部分与大家一起分享: 1、什么是SQLite 2、Android中使用SQLite 一、什么是SQLite SQ...
  • rongwenbin
  • rongwenbin
  • 2014年07月31日 17:37
  • 279

scala第十五讲:迭代器

1:迭代器不是集合,而是访问集合的方法 2:迭代器访问一个元素,所以对内存要求小 3:用it.next()访问下一个元素,用it.hasNext()返回是否有下一个值,有为true,没有就为false...
  • stronglyh
  • stronglyh
  • 2017年12月27日 17:34
  • 47

第十五周 窗口程序体验

// fraDlg.cpp : implementation file // #include "stdafx.h" #include "fra.h" #include "fraDlg.h...
  • liyang201258504411
  • liyang201258504411
  • 2013年06月07日 14:56
  • 503

用户体验设计学习总结(上)

用户体验设计简称UED,是通过一系列的动作文字声音图像表现出该操作功能的特性,主要针对用户的心灵、眼睛、耳朵、触感的设计。并通过这些体验让用户更好的与产品进行交互并达成目的。 首先,UED的一个完整...
  • x970617208
  • x970617208
  • 2017年05月08日 23:13
  • 274
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#锐利体验 第十五讲 特征
举报原因:
原因补充:

(最多只允许输入30个字)