QQ咨询 请直接点击通话王老师 请直接点击通话就业老师 电话咨询 北大青鸟咨询电话

开班截止日

  • 【少量】 9月8日 全日制
  • 【少量】 9月6日 业余制
  • 【热招】 9月15日 全日制
  • 【热招】 9月13日 业余制
  • 公益讲座

    时间:2008年9月7日13点30分
    主题:个人主页设计
    主讲:中心IT讲师
    地点:南昌路47号(雁荡路84号)科学会堂二号楼二楼
    敬请光临!

    中文短信平台:
    编辑 "上海北大青鸟" 至12114
    --------------------------
    报名咨询
    电话:021-53063155
    电话:021-53061138
    免费电话:800-820-1253

    北大青鸟中心地图中心地图

    公交:01 02 24 36 41 42 104 109 126 128 781 786 911 926 930 933隧道八线 大桥一线

    地铁:1号线黄陂南路1号出口即可到达

    当前位置:师资力量 >> 学术论文 >>

    DotNet高级应用:特性和反射(下)

    1. 自定义特性的应用:

    自定义特性是一个特殊的类,它必须遵循两个规范:这个特性类必须派生自System.Attribute;这个类的构造函数只能包含可在编译时解析的类型,如字符串类型或整数类型。
    1、在单元测试软件中,常常需要定义一系列的测试类来检查类,在回归测试中也是如此,希望确保更正一个错误而不必破坏其他的代码。这样就需要提供代码和测试类之间的交叉引用,下面的自定义特性可以帮助跟踪类及其测试类。
    示例:
    using System;
    using System.Reflection;
    namespace UnitTesting
    {    //////////////////////////////自定义特性类//////////////////////////////////////
    [AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
    public class TestCaseAttribute:Attribute
    {
    public readonly System.Type TestCase;//只读成员,用于测试给定类的对象类型,所以使用System.Type类型成员
    public TestCaseAttribute(System.Type testCase) //构造函数
    {TestCase=testCase;}
    public void Test()
    {            
    object obj=Activator.CreateInstance(TestCase); //创建TestCase实例
    }
    }
    ///////////////////////////////测试一个对象TestAnObject///////////////////////
    [TestCase(typeof(TestAnObject))]
    public class SomeCode
    {
    public SomeCode()
    {}
    public int Do()
    {return 999;}
    }

         ////////////////////////////////////测试类////////////////////////////////////////
    public class TestAnObject
    {
    public TestAnObject()
    {
    SomeCode scode=new SomeCode();
    if(scode.Do()!=999)
    {
    throw new Exception("错误");
    }
    }
    }

         ///////////////////////////////主程序代码////////////////////////////////////////
    public class UnitTest
    {
    public static void Main()
    {
    Assembly asm=Assembly.GetExecutingAssembly();//获取当前代码所在的组件
    System.Type[] types=asm.GetExportedTypes();//获取组件asm中定义的导出类型,将找到类TestCaseAttribute
    foreach(System.Type type in types)
    {
    Console.WriteLine("Checking type {0}",type.ToString());//打印出测试对象的类型,这里将打印出类型SomeCode类型
    //获取SomeCode类中由System.Type标识别的所有的自定义的特性,并放在数组里
    object[] atts=type.GetCustomAttributes(typeof(TestCaseAttribute),false);
    if(1==atts.Length)//检查是否有自定义特性在数组里
    {
    Console.WriteLine("找到TestCaseAttribute特性,开始测试...");
    TestCaseAttribute tca=atts[0] as TestCaseAttribute;
    try
    {
    tca.Test();//创建测试用例类型的实例,如果成功,则测试通过
    Console.WriteLine("测试通过");
    }
    catch(Exception ex)
    {
    Console.WriteLine("测试没通过");
    Console.WriteLine(ex.ToString());
    }
    }
    }
    }
    }
    }
    示例代码补充解释:
    自定义特性TestCase通过代码行[AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
    说明此类要使用系统内置特性:AttributeUsage
    AttributeTargets.Class是系统特性AttributeUsage的构造函数的第一个参数,指明自定义特性的作用域,这里限定自定义特性使用在类上,AttributeTargets是一个枚举,其他可以选择的值有:
    All(特性可以在组件的任何地方有效)、Assembly(特性在组件上有效)、Constructor(特性在类的构造函数上有效)、Delegate(特性在委托中有效)、Event(特性在事件定义上有效)、Field(特性可以放在内部成员上)、InterFace(特性在接口上有效)、Method(特性在方法上有效)。使用多个枚举值时,使用或”|”连接。
    AllowMultiple=false不能给元素添加一个以上相同的特性。
    Inherited=true标志自定义的特性是可以继承的。
    ★ 上面的代码通过创建自定义特性来交叉引用测试类和代码类,其中用到了系统特性[AttributeUsage]
    下面将使用自定义的特性在.NET类中生成数据库模式(包括表、列和数据类型)
    2、如果数据库变化不是很频繁,使用自定义特性可以提供一种高效的访问数据库的方式。
    示例:
    using System;
    using System.Data;
    using System.Collections;
    using System.Reflection;
    namespace DBAttribute
    {
    //////////////////////////////////////自定义特性类的定义:此特性应用于class,不可继承此类,不可重复在一个类上使用多个此属性//////////////////////////////////////////
    [AttributeUsage(AttributeTargets.Class,Inherited=false,AllowMultiple=false)]
    public class DatabaseTableAttribute:Attribute 
    {
    public readonly string TableName;//公共成员,设置table名称
    //构造函数,在使用此自定义特性时,需要传入表名称
    public DatabaseTableAttribute(string tableName) {TableName=tableName;}        
    }
    /////////////////////////自定义特性类的定义:此特性应用于Property,可继承此类,不可重复在一个属性上使用多个此属性////////////////////////////////////////////////////////////
    [AttributeUsage(AttributeTargets.Property,Inherited=true,AllowMultiple=false)]
    public class DatabaseColumnAttribute:Attribute
    {
    public readonly string ColumnName;
    public readonly ColumnDomain DataType;
    public bool Nullable=false;
    public int Order;//确定列的顺序,生成表时,列以升序输出
    public int Size;
    private static int nextOrder=100;
    public DatabaseColumnAttribute(string column,ColumnDomain dataType)
    {
    ColumnName=column;
    DataType=dataType;
    Order=GeneraterOrderNumber();//确定列以升序输出
    }
    public static int GeneraterOrderNumber(){return nextOrder++;}        
    }
    //////////////////////////////定义一个抽象类,继承自DataRow类,其他子类可以从此抽象类继承,对于有几个表中有相同字段的情况比较使用///////////////////////////////////////////////////
    public abstract class GenericRow:DataRow
    {
    public GenericRow(DataRowBuilder builder)
    :base(builder){}//调用基类的构造函数
    //使用自定义的特性创建列,将调用DatabaseColumnAttribute类的构造函数
    [DatabaseColumn("NAME",ColumnDomain.String,Order=10,Size=64)]
    public string Name
    {
    get{return (string)this["NAME"];}
    set{this["NAME"]=value;}
    }
    [DatabaseColumn("DESCRIPTION",ColumnDomain.String,Order=11,Size=1000)]
    public string Description
    {
    get{return (string)this["DESCRIPTION"];}
    set{this["DESCRIPTION"]=value;}
    }
    }
    //////////////////////////////////////////////使用自定义的特性创建表AUTHOR,将调用DatabaseTableAttribute类的构造函数////////////////////////////////////////////////
    [DatabaseTable("AUTHOR")]
    public class AuthorRow:GenericRow//继承自抽象类GenericRow
    {
    public AuthorRow(DataRowBuilder builder)
    :base(builder) {}     
    [DatabaseColumn("AUTHOR_ID",ColumnDomain.Long,Order=1)] //Order=1,AUTHOR_ID是第一列
    public long AuthorID
    {
    get{return (long)this["AUTHOR_ID"];}
    set{this["AUTHOR_ID"]=value;}
    }
    [DatabaseColumn("HIRE_DATE",ColumnDomain.DateTime,Nullable=true)]
    public DateTime HireDate
    {
    get{return (DateTime)this["HIRE_DATE"];}
    set{this["HIRE_DATE"]=value;}
    }       
    }
    ///////////生成SQL,将生成的SQL语句打印在控制台,实际使用时可以不这样打印//////
    public class DatabaseTest
    {
    public static void Main()
    {
    OutPutTable(typeof(AuthorRow));
    }
    public static void OutPutTable(System.Type type)
    {
    object[] tableAttributes=type.GetCustomAttributes(typeof(DatabaseTableAttribute),true);
    if(tableAttributes.Length ==1)
    {
    Console.WriteLine("CREATE TABLE {0}",((DatabaseTableAttribute)tableAttributes[0]).TableName);
    Console.WriteLine("(");
    SortedList columns=new SortedList();
    foreach(PropertyInfo prop in type.GetProperties())
    {
    object[] columnAttributes=prop.GetCustomAttributes(typeof(DatabaseColumnAttribute),true);
    if(columnAttributes.Length ==1)
    {
    DatabaseColumnAttribute dca=columnAttributes[0] as DatabaseColumnAttribute;
    string dataType=ConvertDataType(dca);
    columns.Add(dca.Order,string.Format(" {0,-31}{1,-20}{2,8},",dca.ColumnName,dataType,dca.Nullable?"NULL":"NOT NULL"));//格式化输出
    }
    foreach(DictionaryEntry e in columns)//重新排序后输出
    {
    Console.WriteLine(e.Value);
    Console.WriteLine(")");
    Console.WriteLine("GO");
    }
    }
    }            
    }
    //Main函数里调用的方法
    private static string ConvertDataType(DatabaseColumnAttribute dca)
    {
    string dataType=null;
    switch(dca.DataType)//依据枚举将类型转化为数据库特定的类型
    {
    case ColumnDomain.DateTime:
    {
    dataType="DATETIME";break;
    }
    case ColumnDomain.Integer:
    {
    dataType="INT";break;
    }
    case ColumnDomain.Long:
    {
    dataType="BIGINT"; break;
    }
    case ColumnDomain.String:
    {
    dataType=string.Format("VARCHAR({0})",dca.Size);break;
    }                 
    }
    return dataType;
    }
    }
    //枚举定义
    public enum ColumnDomain
    {
    Integer,
    Long,
    String,
    DateTime
    }
    }
    说明:上例中多斜线注释(如:“////////“)都是类的的注释

    友情提示:如果您对北大青鸟的学费、课程、就业有疑问,可以拨打免费电话: 800-820-1253 和我们北大青鸟联系!政府注资并监管,就业有保障。也可直接 QQ交谈请直接点击通话王老师

    在线客服
    网站客服