Pages

Search

Friday, February 24, 2012

Custom Attributes


Custom attribute enables the capability of creating user defined attributes (types) extending “Attribute” class. Custom attribute helps to tag a property or class or method to identify the respective members at run time based on type.
Below Example helps to understand better.
In below example, the same business object can be used in 2 different entities to invoke actions specific to entity.
Class which has methods to read property values based on type.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace BusinessAttributes
{
    public class Attribute
    {
        //To read the value of a given property and type
        public object ReadPropertyValue(Object argBusinessObject, Type atrType)
        {
            Type objType = argBusinessObject.GetType();
            var properties = (from memInfo in objType.FindMembers(MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, null, null)
                              where memInfo.GetCustomAttributes(atrType, true).Count() > 0 &&
                              memInfo.GetCustomAttributes(atrType, true).All((o) =>
                              { if (o.ToString().Trim().ToUpper() == atrType.ToString().Trim().ToUpper()) { return true; } return false; })
                              select memInfo);
            if (properties.Count() == 0)
                throw new Exception("Business Property of type \"" + atrType.ToString() + "\" not found");
            if (properties.Count() > 1)
                throw new Exception("Business Property of type \"" + atrType.ToString() + "\"  found more than one");
            return objType.InvokeMember(properties.First().Name, BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public, null, argBusinessObject, null);

        }

        //To return custom attribute objects list
        public IList<Object> GetCustomAttribute(Object argBusinessObject, Type atrType)
        {
            Type objType = argBusinessObject.GetType();

            var properties = (from memInfo in objType.FindMembers(MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, null, null)
                              where memInfo.GetCustomAttributes(atrType, true).Count() > 0 &&
                              memInfo.GetCustomAttributes(atrType, true).All((o) =>
                              { if (o.ToString().Trim().ToUpper() == atrType.ToString().Trim().ToUpper()) { return true; } return false; })
                              select memInfo);
            if (properties.Count() == 0)
                throw new Exception("Business Property of type \"" + atrType.ToString() + "\" not found");
            if (properties.Count() > 1)
                throw new Exception("Business Property of type \"" + atrType.ToString() + "\"  found more than one");
            var customAttribute =
            (from att in properties.First().GetCustomAttributes(atrType, true)
             where att.GetType().ToString().Trim().ToUpper() == atrType.ToString().Trim().ToUpper()
             select att);
            return customAttribute.ToList();
        }
    }
}


Logger (Entity) class extending the BusinessAttributes.Attribute class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace DBLogger
{
    public class Logger : BusinessAttributes.Attribute
    {
        public Object LogObject
        {
            set;
            get;
        }
        //reading the employee details from object based on custom attribute type
        public string ReadDetails()
        {
            return "Log Information - " + ReadPropertyValue(LogObject, typeof(DBLogger.LogID)) + " - " + ReadPropertyValue(LogObject, typeof(DBLogger.LogDesc));
        }
    }
    public class LogID : Attribute { };
    public class LogDesc : Attribute { };
}


Employee  (Entity) class extending the BusinessAttributes.Attribute class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace EmployeeLib
{
    public class Employee : BusinessAttributes.Attribute
    {
        public Object EmployeeObject
        {
            set;
            get;
        }
        //reading the employee details from object based on custom attribute type
        public string ReadDetails()
        {
            IList<Object> dt = GetCustomAttribute(EmployeeObject, typeof(EmpID));
            EmpID objEmpID = dt[0] as EmpID;
            if (objEmpID.isActive)
                return "Employee Information (Active) - " + ReadPropertyValue(EmployeeObject, typeof(EmpID)) + " - " + ReadPropertyValue(EmployeeObject, typeof(EmpName));
            else
                return "Employee Information (Inactive) - " + ReadPropertyValue(EmployeeObject, typeof(EmpID)) + " - " + ReadPropertyValue(EmployeeObject, typeof(EmpName));
        }
    }

    public class EmpID : Attribute
    {
        public bool isActive { get; set; }

        public EmpID(bool blnActive)
        {
            isActive = blnActive;
        }
    };
    public class EmpName : Attribute
    { };
}

User Interface (Windows form)

//The common business object which can be used in 2 entities
        CommonBA objCommonBA = null;

        //when used clicks on "Log" button
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                //creating an object for Log entity and setting the shared business object as Log Object
                DBLogger.Logger objLogger = new DBLogger.Logger() { LogObject = objCommonBA };
                //displaying the details of the log object
                MessageBox.Show(objLogger.ReadDetails());
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }

        //when used clicks on "Employee" button
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                //creating an object for Employee entity and setting the shared business object as Employee object
                EmployeeLib.Employee objEmp = new EmployeeLib.Employee() { EmployeeObject = objCommonBA };
                //displaying the employee details.
                MessageBox.Show(objEmp.ReadDetails());
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }

        //on form load
        private void Form1_Load(object sender, EventArgs e)
        {
            //creating the shared business object
            objCommonBA = new CommonBA() { ID = 1234, Desc = "srinivas" };
        }
    }

    //The Business class
    public class CommonBA
    {
        [DBLogger.LogID]
        [EmployeeLib.EmpID(true)]
        //ID attribute and tagged that this property can be used as Log ID in case of
        //log entity and the same as employee id in employee entity
        public int ID
        {
            get;
            set;
        }

        [DBLogger.LogDesc]
        [EmployeeLib.EmpName]
        //Desc attribute and tagged that this property can be used as Log Description in case of
        //log entity and the same as employee name in employee entity
        public string Desc
        {
            get;
            set;
        }
    }

No comments:

Post a Comment