特性提供功能强大的方法。用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。
特性与程序实体关联后,就可以在执行时使用名为“反射”的技术查询特性。
特性的应用
(1).net中特性用来处理多种问题,比方序列化、程序的安全特性、防止即时编译器对程序代码进行优化从而代码easy调试等等。
定制特性的本质上是一个类的元素上去加入附加信息,并在执行其通过反射得到该附加信息(在使用数据实体对象时经经常使用到)
(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语句,这也是前人栽树后人乘凉的事.一个人写好了这些东西,其余的人想用的话直接调用方法传递个实体即可.这才是真正的化繁为简吧!