Attribute与应用
分类索引:C# 语言和运行时剖析--前言
在本章第三节中,笔者采用了自己项目中使用过的一个案例。
实现分为四个部分:1. 在自定义Class的属性上标记DisplayName和Editable标记。2.通过一个泛型的解析器来解析自定义Class的所有属性,将每个属性转化为DataTable的一列,DisplayName转化为ColumnName, Editable转化为Column的ReadOnly属性。3.达到目的:a.自动生成DataTable的架构。b.自动将一个Class的实例Entity转化为一行DataRow.c.自动将一行DataRow转化为一个实例Entity。4.通过VSTO在EXCEL前端显示和操作DataTable。
文章导航
Attribute的概念
一.定义:Attribute是用于描述其使用对象的附加信息的类型。
二.要点:Attribute是一种声明性的为代码添加附加信息的技术。使用该技术,可以在很多场景避免硬编码和使用配置文件。
- Attribute的应用范围定义在System.AttributeTargets枚举中,具体包括:
Assembly | Module | Class | Struct | Enum | Constructor | Method | Property |
Field | Event | Interface | Parameter | Delegate | ReturnValue | GenericParameter |
- 使用Attribute来定制程序的附加信息时,需要配套的使用.NET中的反射机制来获取Attribute中所包含的信息,来动态改变代码的执行方式。这一步非常重要。
- 在.NET中的很多框架和技术都大量应用了Attribute。例如在ASP.NET中在验证;缓存;异常处理;Action上下文处理等场景大量使用的Filter就是对Attribute使用的极好示例。甚至Controller本身也是也实现了各个Filter接口。
Attribute的使用
一.Attribute的使用过程
- 自定义Attribute或者选择系统已封装的Attribute。
- 在需要的对象上附加Attribute信息。(实例化)。
- 自定义方法解析对象的Attribute信息并利用信息获取想达到的效果。
二.自定义Attribute示例
- 使用场景:标记一个账户是否存款账户,支票账户或者佣金账户。
- 要点:
- 使用AttributeUsage来修饰自定义Attribute。
- 定义方式跟普通类型差不多,可以重载构造器以满足附加实例化的需要。
- 示例如下:
[Flags] private enum Accounts { Savings = 0x0001, Checking = 0x0002, Brokerage = 0x0004 } [AttributeUsage(AttributeTargets.Class)] private sealed class AccountsAttribute : Attribute { private Accounts m_accounts; public AccountsAttribute(Accounts accounts) { m_accounts = accounts; } public override Boolean Match(Object obj) { if (obj == null) return false; if (this.GetType() != obj.GetType()) return false; AccountsAttribute other = (AccountsAttribute)obj; // Compare the fields as you see fit // This example checks if 'this' accounts is a subset // of other's accounts if ((other.m_accounts & m_accounts) != m_accounts) return false; return true; // Objects match } public override Boolean Equals(Object obj) { if (obj == null) return false; if (this.GetType() != obj.GetType()) return false; AccountsAttribute other = (AccountsAttribute)obj; // Compare the fields to see if they have the same value // This example checks if 'this' accounts is the same // as other's accounts if (other.m_accounts != m_accounts) return false; return true; // Objects are equal } // Override GetHashCode since we override Equals public override Int32 GetHashCode() { return (Int32)m_accounts; } }
三.实例化Attribute(附加Attribute信息)
示例如下:
[Accounts(Accounts.Savings)] private sealed class ChildAccount { } [Accounts(Accounts.Savings | Accounts.Checking | Accounts.Brokerage)] private sealed class AdultAccount { }
四.使用反射检测与执行
示例如下:
public static void Go() { CanWriteCheck(new ChildAccount()); CanWriteCheck(new AdultAccount()); } private static void CanWriteCheck(Object obj) { // Construct an instance of the attribute type and initialize it // to what we are explicitly looking for. Attribute checking = new AccountsAttribute(Accounts.Checking); // Construct the attribute instance that was applied to the type Attribute validAccounts = Attribute.GetCustomAttribute( obj.GetType(), typeof(AccountsAttribute), false); // If the attribute was applied to the type AND the // attribute specifies the "Checking" account, then the // type can write a check if ((validAccounts != null) && checking.Match(validAccounts)) { Console.WriteLine("{0} types can write checks.", obj.GetType()); } else { Console.WriteLine("{0} types can NOT write checks.", obj.GetType()); } }
项目实践
一.定义一个需要被清单化的类型
public class InspectionEntity { #region Member private string inspectionType; private string notesFormType; private string documentUniId; private string documentCustomId; private string documentFieldName; private string fieldCurrentValue; private string fieldCorrectValue; private ValueStateFlag valueState; private string valueStateRemark; #endregion [Editable(false)] [DisplayName("检查类型")] public string InspectionType { get { return inspectionType; } set { inspectionType = value; } } [Editable(false)] [DisplayName("表单类型")] public string NotesFormType { get { return notesFormType; } set { notesFormType = value; } } [Editable(false)] [DisplayName("文档UniversalID")] public string DocumentUniID { get { return documentUniId; } set { documentUniId = value; } } [Editable(false)] [DisplayName("文档自定义编号")] public string DocumentCustomID { get { return documentCustomId; } set { documentCustomId = value; } } [Editable(false)] [DisplayName("文档域名")] public string DocumentFieldName { get { return documentFieldName; } set { documentFieldName = value; } } [Editable(false)] [DisplayName("现有值")] public string FieldCurrentValue { get { return fieldCurrentValue; } set { fieldCurrentValue = value; } } [DisplayName("正确值")] public string FieldCorrectValue { get { return fieldCorrectValue; } set { fieldCorrectValue = value; } } [DisplayName("数据状态")] public ValueStateFlag ValueState { get { return valueState; } set { valueState = value; } } [DisplayName("数据状态描述")] public string ValueStateRemark { get { return valueStateRemark; } set { valueStateRemark = value; } } }
二.定义一个泛型的解析器类型,将自定义类型与DataTable中的结构相互转化
public sealed class DataTableReflection<T> where T : class, new() { //根据类型T自动解析DataTalbe的Column架构 public DataTable InitialEntityTable(string tableName) { try { DataTable table = new DataTable(tableName); PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance); foreach (var property in properties) { DataColumn column = new DataColumn(); object[] attributes = property.GetCustomAttributes(typeof(DisplayNameAttribute), false); if (attributes.Count() > 0) column.ColumnName = ((DisplayNameAttribute)attributes[0]).DisplayName; attributes = property.GetCustomAttributes(typeof(EditableAttribute), false); if (attributes.Count() > 0) column.ReadOnly = !((EditableAttribute)attributes[0]).AllowEdit; column.DataType = property.PropertyType; table.Columns.Add(column); } return table; } catch { throw; } } //根据DataRow自动解析类型实例Entity public T ConvertDataRowToEntity(DataRow row) { try { T entity = Activator.CreateInstance<T>(); PropertyInfo[] properties = typeof(T).GetProperties(); foreach (var property in properties) { object[] attributes = property.GetCustomAttributes(typeof(DisplayNameAttribute), false); if (attributes.Count() > 0) { string columnName = ((DisplayNameAttribute)attributes[0]).DisplayName; if (!row.IsNull(columnName)) property.SetValue(entity, row[columnName], null); } } return entity; } catch { throw; } } //根据类型实例Entity自动解析DataRow public void ConvertEntityToDataRow(T entity, ref DataRow row) { try { PropertyInfo[] properties = typeof(T).GetProperties(); foreach (var property in properties) { object[] attributes = property.GetCustomAttributes(typeof(DisplayNameAttribute), false); if (attributes.Count() > 0) { string columnName = ((DisplayNameAttribute)attributes[0]).DisplayName; if (row[columnName] == DBNull.Value || !row.Table.Columns[columnName].ReadOnly) row[columnName] = property.GetValue(entity, null); } } } catch { throw; } } }
三.项目实现效果图(灰色列代表不可编辑)