特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体关联后,即可在运行时使用名为“反射”的技术查询特性。
特性的应用
(1).net中特性用来处理多种问题,比如序列化、程序的安全特性、防止即时编译器对程序代码进行优化从而代码容易调试等等。
定制特性的本质上是一个类的元素上去添加附加信息,并在运行其通过反射得到该附加信息(在使用数据实体对象时经常用到)
(2)Attribute作为编译器的指令时的应用
Conditional:起条件编译的作用,只有满足条件,才允许编译器对它的代码进行编译。一般在程序调试的时候使用
DllImport:用来标记费.net的函数,表明该方法在一个外部的DLL中定义。
Obsolete: 这个属性用来标记当前的方法已经废弃,不再使用
CLSCompliant: 保证整个程序集代码遵守CLS,否则编译将报错。
特性的原理
[Table(Name="dbo.[User]")]
public partial class User
{
}
当C#编译器发现这个属性有一个特性Table时,首先会把字符串Attribute添加到这个名称的后面,形成一个组合名称TableAttribute,然后在其搜索路径的所有命名空间中搜索有相同类名的类。但要注意,如果该特性名结尾是Attribute,编译器就不会把该字符串加到组合名称中。所有的特性都是从System.Attribute类型上面派生的。
接着我们来看一下Table特性的定制格式:
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = false,AllowMultiple = false)]
public class TableAttribute : Attribute
{
//保存表名的字段
private string _tableName;
public TableAttribute()
{
}
public TableAttribute(string tableName)
{
this._tableName = tableName;
}
/// <summary>
/// 映射的表名(表的全名:模式名.表名)
/// </summary>
public string TableName
{
set
{
this._tableName = value;
}
get
{
return this._tableName;
}
}
}
解释:
其实要解释也就一句话:AttributeUsageAttribute是一个类,括号内是带参数的构造函数的参数.我们看看这个类的定义就明白了
namespace System
{
// 摘要:
// 指定另一特性类的用法。无法继承此类。
[Serializable]
[ComVisible(true)]
[AttributeUsage(AttributeTargets.Class,Inherited = true)]
public sealed class AttributeUsageAttribute: Attribute
{
// 摘要:
// 用指定的System.AttributeTargets、System.AttributeUsageAttribute.AllowMultiple
// 值和 System.AttributeUsageAttribute.Inherited 值列表初始化System.AttributeUsageAttribute
// 类的新实例。
//
// 参数:
// validOn:
// 使用按位“或”运算符组合的一组值,用于指示哪些程序元素是有效的。
publicAttributeUsageAttribute(AttributeTargets validOn);
// 摘要:
// 获取或设置一个布尔值,该值指示能否为一个程序元素指定多个指示特性实例。
// 补: 这个属性标记了我们的定制特性能否被重复放置在同一个程序实体前多次
//
// 返回结果:
// 如果允许指定多个实例,则为 true;否则为 false。默认为 false。
public bool AllowMultiple { get; set; }
//
// 摘要:
// 获取或设置一个布尔值,该值指示指示的特性能否由派生类和重写成员继承。
// 补: 这个属性标记了我们的定制特性能否被重复放置在同一个程序实体前多次
//
// 返回结果:
// 如果该特性可由派生类和重写成员继承,则为 true,否则为 false。默认为 true。
// 补:我们可以使用这个属性来控制定制特性的继承规则。它标记了我们的特性能否被继承。
public bool Inherited { get; set; }
//
// 摘要:
// 获取一组值,这组值标识指示的特性可应用到的程序元素。
//
// 返回结果:
// 一个或多个 System.AttributeTargets 值。默认为 All。
public AttributeTargets ValidOn { get;}
}
}
特性也是一个Class类型,可以有多个构造函数,就像C#的new语句一样,我们向类型附加特性时可以使用不同的初始化参数来指明使用特性的那个构造函数。我们附加特性时还可以使用“属性名=属性值”的方法来直接指明特性的属性值。该特性中定义了一个TableName属性,该属性就是被修饰的对象所映射的数据库表的名称。
下面我们举一个使用特性来进行O/RMapping的例子,也就是将对象转化成Sql语句
用户类:
[Table("User")]
public class User
{
[Colum("userID", DbType =DbType.Int32)]
public int UserID { get; set; }
[Colum("UserName", DbType =DbType.String)]
public string UserName { get; set; }
}
//列特性
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = false,AllowMultiple = false)]
public class TableAttribute : Attribute
{
//保存表名的字段
private string _tableName;
public TableAttribute()
{
}
public TableAttribute(string tableName)
{
this._tableName = tableName;
}
/// <summary>
/// 映射的表名(表的全名:模式名.表名)
/// </summary>
public string TableName
{
set
{
this._tableName = value;
}
get
{
return this._tableName;
}
}
}
//列特性
[AttributeUsageAttribute(AttributeTargets.Property, Inherited = false,AllowMultiple = false)]
public class ColumAttribute : Attribute
{
private string _columName;
private DbType _dbType;
public ColumAttribute()
{
}
public ColumAttribute(string columName)
: this()
{
this._columName = columName;
}
public ColumAttribute(string columName,DbType dbType)
: this(columName)
{
this._dbType = dbType;
}
//列名
public virtual string ColumName
{
set
{
this._columName = value;
}
get
{
return this._columName;
}
}
//描述一些特殊的数据库类型
public DbType DbType
{
get { return _dbType; }
set { _dbType = value; }
}
}
//sql与实体的映射类
public class ORMHelp
{
public void Insert(object table)
{
//获取传入的实体的类型
Type type = table.GetType();
//定义一个字典来存放表中字段和值的对应序列
Dictionary<string, string>columValue = new Dictionary<string, string>();
//用于存放Sql语句
StringBuilder SqlStr = newStringBuilder();
SqlStr.Append("insert into");
//获取实体类前边所有打上的特性标签
TableAttribute temp =(TableAttribute)type.GetCustomAttributes(typeof(TableAttribute),false).First();
//得到表名子
SqlStr.Append(temp.TableName);
SqlStr.Append("(");
//获取类中所有的公用属性
PropertyInfo[] Propertys =type.GetProperties();
foreach (var item in Propertys)
{
//获取被打上标签特性的数组
object[] attributes =item.GetCustomAttributes(false);
foreach (var item1 inattributes)
{
//获得相应属性的值
string value =table.GetType().InvokeMember(item.Name,System.Reflection.BindingFlags.GetProperty, null, table, null).ToString();
ColumAttribute colum =item1 as ColumAttribute;
if (colum != null)
{
//添加到字典中
columValue.Add(colum.ColumName, value);
}
}
}
//拼插入操作字符串
foreach (var item in columValue)
{
SqlStr.Append(item.Key);
SqlStr.Append(",");
}
SqlStr.Remove(SqlStr.Length - 1,1);
SqlStr.Append(")values('");
foreach (var item in columValue)
{
SqlStr.Append(item.Value);
SqlStr.Append("','");
}
SqlStr.Remove(SqlStr.Length - 2,2);
SqlStr.Append(")");
Console.WriteLine(SqlStr.ToString());
}
}
前端使用代码:
public class project
{
static void Main(string[] args)
{
ORMHelp o = new ORMHelp();
User u = new User() { UserID = "de23sdcs",UserName = "Bema" };
o.Insert(u);
}
}
最终SqlStr中的内容为insertinto User(userID,UserName) values('de23sdcs','Bema');
也需看着这段代码很复杂,却得出了一个如此简单的sql语句,这也是前人栽树后人乘凉的事.一个人写好了这些东西,其余的人想用的话直接调用方法传递个实体就行.这才是真正的化繁为简吧!