Attribute 类将预定义的系统信息或用户定义的自定义信息与目标元素相关联。 目标元素可以是程序集、类、构造函数、委托、枚举、事件、字段、接口、方法、可移植可执行文件模块、参数、属性、返回值、结构或其他特性。
特性所提供的信息也称为元数据。元数据可由应用程序在运行时进行检查以控制程序处理数据的方式,也可以由外部工具在运行前检查以控制应用程序处理或维护自身的方式。
所有特性类型都直接或间接地从 Attribute 类派生。 特性可应用于任何目标元素;多个特性可应用于同一目标元素;并且特性可由从目标元素派生的元素继承。使用 AttributeTargets 类可以指定特性所应用到的目标元素。
以下用一个类似于Hibernate中Session的Save()方法效果,自动持久化对象信息到数据库来说明自定义特性的使用
案例说明:
1. 建立Dept表
Create Table Dept(
deptNo int identity(1,1) primary key,
dname nvarchar(10) not null,
description nvarchar(100)
)
Go
2. 自定义特性类
/**************自定义特性类*****************/
///<summary>
/// 作用:用来说明表名是什么
/// AttributeUsage:说明特性的目标元素是什么
/// AttributeTargets.Class:代表目标元素为Class
///</summary>
[AttributeUsage(AttributeTargets.Class)]
public class TableAttribute : Attribute{
///<summary>
/// 表名
///</summary>
public string TableName { get; set; }
#region 构造方法,可选的
public TableAttribute() { }
public TableAttribute(string tableName) {
this.TableName = tableName;
}
#endregion
}
/**************自定义特性类*****************/
///<summary>
/// 作用:说明列是否为自动增长列
///</summary>
[AttributeUsage(AttributeTargets.Property)]
class IdentityAttribute: Attribute
{
///<summary>
/// true:是; false:否
///</summary>
public bool IsIdentity { get; set; }
}
/****************实体类***************/
///<summary>
/// 有意将类名定义成与表名不一致
/// 用Table特性来说明实体类对应的表名是什么
///</summary>
[Table(TableName = "Dept")]
public class Department {
///<summary>
/// 部门编号,用特性标注为自动增长
///</summary>
[Identity(IsIdentity=true)]
public int DeptNo { get; set; }
///<summary>
/// 部门名称
///</summary>
public string Dname { get; set; }
///<summary>
/// 部门描述
///</summary>
public string Description { get; set; }
public Department( string name, string desc) {
Dname = name;
Description = desc;
}
}
/****************执行持久化操作类***************/
///<summary>
/// 执行持久化操作类
///</summary>
public class ADOManager {
///<summary>
/// 将对象的属性值作为表中对应列的值来添加
///</summary>
///<param name="obj">要添加的对象</param>
public int Save(Object obj) {
//1.取得类名:代表表名,用到反射
string tableName = obj.GetType().Name;
//如果类有TableAttribute特性,在采用特性说明的类名
TableAttribute attr = Attribute.GetCustomAttribute(obj.GetType(), typeof(TableAttribute)) as TableAttribute;
if (attr != null) {//说明类加了Table特性
tableName = attr.TableName;//取得表名
}
//sql语句模板:insert into Dept(deptno,dname,description) values('2','','');
StringBuilder sql = new StringBuilder("insert into ");
sql.Append(tableName);
sql.Append(" (");
//循环对象的属性名:取得列名
foreach (PropertyInfo item in obj.GetType().GetProperties()) {
//取得是否有自动增长的特性
IdentityAttribute att = Attribute.GetCustomAttribute(item, typeof(IdentityAttribute)) as IdentityAttribute;
if (att == null || !att.IsIdentity) {//没有,则添加列
sql.Append(item.Name);
sql.Append(",");
}
}
//去除最后一个逗号'
sql.Remove(sql.Length - 1, 1);
sql.Append(") values(");
//循环取出对象的属性值:为列赋值
foreach (PropertyInfo item in obj.GetType().GetProperties()) {
//取得是否有自动增长的特性
IdentityAttribute att = Attribute.GetCustomAttribute(item, typeof(IdentityAttribute)) as IdentityAttribute;
if (att == null) {//没有,则追加列的值
//GetValue():obj代表什么对象,null代表没有参数
sql.Append("'" + item.GetValue(obj, null) + "'");
sql.Append(",");
}
}
//去除最后一个逗号'
sql.Remove(sql.Length - 1, 1);
sql.Append(")");
//查看完整的sql语句
Console.WriteLine(sql.ToString());
//执行sql语句
SqlConnection conn = new SqlConnection("server=.;database=test;integrated security=true");
SqlCommand comm = new SqlCommand(sql.ToString(), conn);
conn.Open();
int r = comm.ExecuteNonQuery();
conn.Close();
return r;//返回执行结果
}
}
/****************测试类关键代码***************/
Department dept = new Department("开发部", "负责产品的研发");
ADOManager manager = new ADOManager();
int r = manager.Save(dept);
Console.WriteLine(r==0?"失败":"成功");
小结:
C#的特性类和Java中的元注释一样
特性其本质就是一个继承了Attribute的类
使用使可以省略Attribute结尾,如:TableAttribute =>> Table
特性将会影响其作用的目标元素的编译和运行过程
使用自定义特性的步骤:
1. 定义特性类,类必须直接或间接继承字Attribute类
2. 在需要用的该特性的目标元素上添加特性
3. 在使用添加了特性的类的使用,获取并使用自特定特性的信息