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的使用过程

  1. 自定义Attribute或者选择系统已封装的Attribute。
  2. 在需要的对象上附加Attribute信息。(实例化)。
  3. 自定义方法解析对象的Attribute信息并利用信息获取想达到的效果。 

 

二.自定义Attribute示例

  1. 使用场景:标记一个账户是否存款账户,支票账户或者佣金账户。
  2. 要点:
    • 使用AttributeUsage来修饰自定义Attribute
    • 定义方式跟普通类型差不多,可以重载构造器以满足附加实例化的需要。
  3. 示例如下:
   [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;
            }
        }
    }

 

三.项目实现效果图(灰色列代表不可编辑)

截图00

posted @ 2013-01-14 15:18  simon_developer  阅读(2513)  评论(1编辑  收藏  举报