-
C#特性Attribute的应用
文章内容参考了nuaaflm的反射学习系列2-特性(Attribute),链接地址为:http://www.cnblogs.com/nuaalfm/archive/2008/09/07/1286195.html
因为打算写一个简单的ORM实现,所以上网上参考了些资料,现在先介绍一下需要用到的一个重要的技术,特性(Attribute)。因为原文的作者已经介绍得很详细了,我就不自己写了,直接COPY过来。由于原作者使用的是.net3.5的,我把代码改成了2.0的版本。
先看一个简单的例子
[Table(Name="UserInfo")]
public class UserInfo
{
当C#编译器发现这个属性有一个特性Table时,首先会把字符串Attribute添加到这个名称的后面,形成一个组合名称TableAttribute,然后在其搜索路径的所有命名空间中搜索有相同类名的类。但要注意,如果该特性名结尾是Attribute,编译器就不会把该字符串加到组合名称中。所有的特性都是从System.Attribute类型上面派生的。
接着我们来看一下Table特性的定制格式
[AttributeUsageAttribute(AttributeTargets.Class, Inherited=true,AllowMultiple=false)]
public class TalbeAttribute:Attribute
{
在定义类型时使用System.AttributeUsage特性来表明这个自定义特性的使用范围,这里使用了Class样式,表示TableAttribute特性只能用在其它的Class类型前面,若放置在Interface或Struct类型前面,或者放在对象成员的前面则会出现编译错误。这里还是用语句 AllowMultiple=false 语句来表明对于一个类型,该特性只能用一次,若一个Class类型前面出现多个TableAttribute,则会出现编译错误。若设置AllowMultiple=true,则该特性可以多次定义,也就是一个Class类型前面可以出现多个相同类型的特性。不过这里我们假设一个对象只能映射到一个数据表上,没有多重映射,因此就指明对同一个类型该特性不能多次使用。Inherited参数设定为true,就表示应用到类或接口上的特性也可以自动应用到所派生的类或接口上。
我们再看一下定制TalbeAttribute特性的完整例子:
Code
[AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=false)]
public class TableAttribute : Attribute
{
private string tableName;
public string TableName
{
get { return tableName; }
set { tableName = value; }
}
public TableAttribute()
{
this.tableName = null;
}
public TableAttribute(string tableName)
{
this.tableName = tableName;
}
}
特性也是一个Class类型,可以有多个构造函数,就像C#的new语句一样,我们向类型附加特性时可以使用不同的初始化参数来指明使用特性的那个构造函数。我们附加特性时还可以使用“属性名=属性值”的方法来直接指明特性的属性值。该特性中定义了一个TableName属性,该属性就是被修饰的对象所映射的数据库表的名称。
下面我们举一个使用特性来进行O/RMapping的例子
用户类:
Code
[Table("UserInfo")]
public class UserInfo
{
private int userId;
[Column("UserId",DbType.Int32)]
public int UserId
{
get { return userId; }
set { userId = value; }
}
private string userName;
[Column(UserName,DbType.String)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
}
列特性:
Code
[AttributeUsage(AttributeTargets.Property,AllowMultiple=false,Inherited=false)]
public class ColumnAttribute : Attribute
{
public ColumnAttribute()
{
this.columnName = null;
this.dbType = DbType.String;
}
public ColumnAttribute(string columnName)
{
this.columnName = columnName;
}
public ColumnAttribute(string columnName, DbType dbType)
: this(columnName)
{
this.dbType = dbType;
}
private string columnName;
public string ColumnName
{
get { return columnName; }
set { columnName = value; }
}
private DbType dbType;
public DbType DbType
{
get { return dbType; }
set { dbType = value; }
}
}
运行类:
Code
class Program
{
static void Main(string[] args)
{
UserInfo userInfo = new UserInfo();
Type type = userInfo.GetType();
TableAttribute ta = (TableAttribute)type.GetCustomAttributes(false)[0];
Console.WriteLine("数据表名:" + ta.TableName);
PropertyInfo[] infos = type.GetProperties();
foreach (PropertyInfo info in infos)
{
object[] attributes = info.GetCustomAttributes(false);
foreach (object att in attributes)
{
if (att is ColumnAttribute)
{
ColumnAttribute ca = att as ColumnAttribute;
string cn = ca.ColumnName == null ? info.Name : ca.ColumnName;
Console.WriteLine("字段名:" + cn);
Console.WriteLine("字段类型:" + ca.DbType);
}
}
}
}
下面是运行结果的截图:
我们再看一下定制TalbeAttribute特性的完整例子:
Code
[AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=false)]
public class TableAttribute : Attribute
{
private string tableName;
public string TableName
{
get { return tableName; }
set { tableName = value; }
}
public TableAttribute()
{
this.tableName = null;
}
public TableAttribute(string tableName)
{
this.tableName = tableName;
}
}
特性也是一个Class类型,可以有多个构造函数,就像C#的new语句一样,我们向类型附加特性时可以使用不同的初始化参数来指明使用特性的那个构造函数。我们附加特性时还可以使用“属性名=属性值”的方法来直接指明特性的属性值。该特性中定义了一个TableName属性,该属性就是被修饰的对象所映射的数据库表的名称。
下面我们举一个使用特性来进行O/RMapping的例子
用户类:
Code
[Table("UserInfo")]
public class UserInfo
{
private int userId;
[Column("UserId",DbType.Int32)]
public int UserId
{
get { return userId; }
set { userId = value; }
}
private string userName;
[Column(UserName,DbType.String)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
}