Attribute(特性)与AOP

Attribute(特性)与AOP

提到特性,好多人都会疑惑特性(attribute),和注释有什么区别,简单来说,特性是给机器看的,而注释是给人看的。

特性不仅可以影响编译还可以影响运行,而注释只是为了让人更加容易理解、看懂代码而特别加注的解释而已。

那么怎么声明一个特性呢。

特性是一个继承或者间接继承Attribute的类
通常用attribute结尾,那么在使用的时候,可以去掉这个结尾

  public class TableAttribute : Attribute
    {
        private string _TableName = null;

        public TableAttribute(string tableName)
        {
            this._TableName = tableName;
        }

        public string GetTableName()
        {
            return this._TableName;
        }
     }

我们还可以通过特性来约束特性,只需要在声明特性的代码上加约束代码

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]

AttributeTargers:约束特性使用范围;

AllowMultiple:是否允许多行

Inherited:是否允许继承

声明了特性后只需要在代码上加一行 [Table("User")]

   [Table("User")]
    public class UserModel
    {
       
        public int Id { get; set; }
        /// <summary>
        /// 账户
        /// </summary>
        public string Account
        {
            set;
            get;
        }
        /// <summary>
        /// 密码
        /// </summary>
        public string Password
        {
            set;
            get;
        }
        /// <summary>
        /// EMaill
        /// </summary>
        public string Email
        {
            set;
            get;
        }
        /// <summary>
        /// 手机
        /// </summary>
        public string Mobile
        {
            set;
            get;
        }
     }

后面需要做的就是获取到这个table名称。

 public static class Extend
    {
          public static string GetTable<T>(this T t) where T : new()
        {
            Type type = t.GetType();
            object[] oAttribute = type.GetCustomAttributes(true);
            foreach (var item in oAttribute)
            {
                if (item is TableAttribute)
                {
                    TableAttribute attribute = item as TableAttribute;
                    return attribute.GetTableName();
                }
            }
            return type.Name;
        }

    }

最后调用。

 class Program
    {
        static void Main(string[] args)
        {
            string name = user.GetTableName<UserModel>()
        }
    }

特性除了可以添加一些额外信息外,还可以验证信息,

比如验证数据是否在一定的数值范围。

首先声明一个特性

 [AttributeUsage(AttributeTargets.Property)]
    public class IntValidateAttribute : Attribute
    {

        private int _Min = 0;
        private int _Max = 0;

        public IntValidateAttribute(int min, int max)
        {
            this._Min = min;
            this._Max = max;
        }

        public bool Validate(int num)
        {
            return num > this._Min && num < this._Max;
        }

    }

然后在ID属性上加特性

   [IntValidateAttribute(0, 10000)]
   public int Id { get; set; }  

这样就可以通过代码处理,达到验证并保存的目的。

 public static void Save<T>(T t)
        {
            bool isSafe = true;

            Type type = t.GetType();

            foreach (var property in type.GetProperties())
            {
                object[] oAttributeList = property.GetCustomAttributes(true);
                foreach (var item in oAttributeList)
                {
                    if (item is IntValidateAttribute)
                    {
                        IntValidateAttribute attribute = item as IntValidateAttribute;
                        isSafe = attribute.Validate((int)property.GetValue(t));
                    }
                }
                if (!isSafe)
                    break;
            }

            if (isSafe)
                Console.WriteLine("保存到数据库");
            else
                Console.WriteLine("数据不合法");
        }
UserModel user = new UserModel();   
BaseDAL.Save<UserModel>(user); 

特性就是在不改变类的情况下额外的增加信息。

这也是AOP编程的主要思想。

软件设计因为引入面向对象思想而逐渐变得丰富起来。“一切皆为对象”的精义,使得程序世界所要处理的逻辑简化,开发者可以用一组对象以及这些对象之间的关系将软件系统形象地表示出来。而从对象的定义,进而到模块,到组件的定义,利用面向对象思想的封装、继承、多态的思想,使得软件系统开发可以向搭建房屋那样,循序渐进,从砖石到楼层,进而到整幢大厦的建成。应用面向对象思想,在设计规模更大、逻辑更复杂的系统时,开发周期反而能变的更短。自然其中,需要应用到软件工程的开发定义、流程的过程控制,乃至于质量的缺陷管理。但从技术的细节来看,面向对象设计技术居功至伟。然而,面向对象设计的唯一问题是,它本质是静态的,封闭的,任何需求的细微变化都可能对开发进度造成重大影响。

在面向对象中,类的本质还是静态的,在我们声明了一个类后,在以后的修改维护中,随着需求的增加,其实我们还是不愿意去动已经写好的类。

比如说我们有个用户注册类

        public interface IUserProcessor
        {
            void RegUser(User user);
        }
        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
            }
        }

但是后来我们希望在注册前和注册后都要来做一些事。这个时候 又不希望去动这个类,

在这里介绍一种设计模式,装饰器模式。用装饰器的模式去提供一个AOP功能

    public class UserProcessorDecorator : IUserProcessor
        {
            private IUserProcessor UserProcessor { get; set; }//声明一个接口类型变量
            public UserProcessorDecorator(IUserProcessor userprocessor)
            {
                UserProcessor = userprocessor;//创建对象时,直接把对象赋值给变量
            }

            public void RegUser(User user)
            {
                PreProceed(user);
                try
                {
                    this.UserProcessor.RegUser(user);
                }
                catch (Exception)
                {

                    throw;
                }
                PostProceed(user);
            }

            public void PreProceed(User user)
            {
                Console.WriteLine("方法执行前");
            }

            public void PostProceed(User user)
            {
                Console.WriteLine("方法执行后");
            }
        }

装饰器模式实现静态代理
AOP 在方法前后增加自定义的方法

public static void Show()
        {
            User user = new User() { Name = "XiMa", Password = "1234567890" };
            IUserProcessor processor = new UserProcessor();
            processor = new UserProcessorDecorator(processor);//UserProcessor直接赋值给构造函数
            processor.RegUser(user);
        }

最后怎么通过Unity 实现动态代理

首先,通过NuGet加载Unity

Attribute(特性)与AOP

在类文件中引用

using Microsoft.Practices.Unity.InterceptionExtension;//InterceptionExtension扩展
using Microsoft.Practices.Unity;
  public class UnityAOP
    {
        public static void Show()
        {
            User user = new User()
            {
                Name = "XiMa",
                Password = "123123123123"
            };

            IUnityContainer container = new UnityContainer();//声明一个容器
            container.RegisterType<IUserProcessor, UserProcessor>();//声明UnityContainer并注册IUserProcessor
         

            container.AddNewExtension<Interception>().Configure<Interception>()
                .SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor());

            IUserProcessor userprocessor = container.Resolve<IUserProcessor>();

            Console.WriteLine("********************");
            userprocessor.RegUser(user);//调用
            //userprocessor.GetUser(user);//调用
        }

        #region 特性对应的行为
        public class UserHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                User user = input.Inputs[0] as User;
                if (user.Password.Length < 10)
                {
                    return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
                }
                Console.WriteLine("参数检测无误");


                IMethodReturn methodReturn = getNext.Invoke().Invoke(input, getNext);

                //Console.WriteLine("已完成操作");

                return methodReturn;
            }
        }

        public class LogHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                User user = input.Inputs[0] as User;
                string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
                Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", message, DateTime.Now);
                return getNext()(input, getNext);
            }
        }


        public class ExceptionHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                IMethodReturn methodReturn = getNext()(input, getNext);
                if (methodReturn.Exception == null)
                {
                    Console.WriteLine("无异常");
                }
                else
                {
                    Console.WriteLine("异常:{0}", methodReturn.Exception.Message);
                }
                return methodReturn;
            }
        }

        public class AfterLogHandler : ICallHandler
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                IMethodReturn methodReturn = getNext()(input, getNext);
                User user = input.Inputs[0] as User;
                string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
                Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", message, DateTime.Now, methodReturn.ReturnValue);
                return methodReturn;
            }
        }


        public class BeforeLogHandler : ICallHandler
        {
             public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)

            {
                IMethodReturn methodReturn = getNext()(input,getNext);
                User user = input.Inputs[0] as User;
                string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
                Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", message, DateTime.Now, methodReturn.ReturnValue);
                return methodReturn;
            }
        }

        #endregion 特性对应的行为

        #region 特性
        public class UserHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                ICallHandler handler = new UserHandler() { Order = this.Order };
                return handler;
            }
        }

       

        public class LogHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new LogHandler() { Order = this.Order };
            }
        }

        public class ExceptionHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new ExceptionHandler() { Order = this.Order };
            }
        }

        public class AfterLogHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new AfterLogHandler() { Order = this.Order };
            }
        }

        public class BeforeLofHandlerAttribute : HandlerAttribute
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new BeforeLogHandler() { Order=this.Order};
            }
        }
        #endregion 特性

        #region 业务
        [UserHandlerAttribute(Order = 1)]
        [ExceptionHandlerAttribute(Order = 3)]
        [LogHandlerAttribute(Order = 2)]
        [AfterLogHandlerAttribute(Order = 5)]
        public interface IUserProcessor
        {
            void RegUser(User user);
       
        }

        public class UserProcessor : IUserProcessor//MarshalByRefObject,
        {
            public void RegUser(User user)
            {
                Console.WriteLine("用户已注册。");
               
            }
        }
        #endregion 业务

        /*
         TransparentProxyInterceptor:直接在类的方法上进行标记,但是这个类必须继承MarshalByRefObject...不建议用
         VirtualMethod:直接在类的方法上进行标记,但这个方法必须是虚方法(就是方法要带virtual关键字)
         InterfaceInterceptor:在接口的方法上进行标记,这样继承这个接口的类里实现这个接口方法的方法就能被拦截
         */
    }

因为Unity好多都是固定写法,没有什么原理,直接给文件,大家可以自己去调试,尝试一下。