zoukankan      html  css  js  c++  java
  • AOP 面向切面编程

    C# AOP 面向切面编程之 调用拦截

    有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程)
    不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用.
    以下是C#的AOP方法:

    首先建立一个控制台工程

    写一个calc类,里面有add个方法:

    一会将拦截这个方法,对出参,入参进行检查.

    public class Calc 
    {
        public int add(int a, int b)
        {
            return a + b;
        }
    }
    
    
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "";
            Console.WriteLine(new Calc().add(1, 0));
            Console.WriteLine(new Calc().add(2, 3));
            Console.WriteLine(new Calc().add(1, 1));
            Console.ReadKey(true);
        }
    }

    运行效果:

    非常普通

    接着添加一个文件


    里面的代码:
    首先写一个消息接收器类,用来处理拦截到的调用:

    /// <summary>
    /// AOP方法处理类,实现了IMessageSink接口
    /// </summary>
    public sealed class MyAopHandler : IMessageSink
    {
        /// <summary>
        /// 下一个接收器
        /// </summary>
        public IMessageSink NextSink { get; private set; }
        public MyAopHandler(IMessageSink nextSink)
        {
            this.NextSink = nextSink;
        }
    
        /// <summary>
        /// 同步处理方法
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public IMessage SyncProcessMessage(IMessage msg)
        {
            //方法调用消息接口
            var call = msg as IMethodCallMessage;
    
            //只拦截指定方法,其它方法原样释放
            if (call == null || (Attribute.GetCustomAttribute(call.MethodBase, typeof(AOPMethodAttribute))) == null || call.MethodName != "add") return NextSink.SyncProcessMessage(msg);
    
            //判断第2个参数,如果是0,则强行返回100,不调用方法了
            if (((int)call.InArgs[1]) == 0) return new ReturnMessage(100, call.Args, call.ArgCount, call.LogicalCallContext, call);
    
            //判断第2个参数,如果是1,则参数强行改为50(失败了)
            //if (((int)call.InArgs[1]) == 1) call = new MyCall(call, call.Args[0], 50);//方法1  失败了
            //if (((int)call.InArgs[1]) == 1) call.MethodBase.Invoke(GetUnwrappedServer(), new object[] { call.Args[0], 50 });//方法2 (无法凑够参数)
    
            var retMsg = NextSink.SyncProcessMessage(call);
    
            //判断返回值,如果是5,则强行改为500
            if (((int)(retMsg as IMethodReturnMessage).ReturnValue) == 5) return new ReturnMessage(500, call.Args, call.ArgCount, call.LogicalCallContext, call);
    
            return retMsg;
        }
    
        /// <summary>
        /// 异步处理方法(暂不处理)
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="replySink"></param>
        /// <returns></returns>
        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) => null;
    }

    然后声明两个特性,用来指明我们要拦截的Methot,以及它所在的Class:

    /// <summary>
    /// 贴在方法上的标签
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public sealed class AOPMethodAttribute : Attribute { }
    
    /// <summary>
    /// 贴在类上的标签
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
    public sealed class AOPAttribute : ContextAttribute, IContributeObjectSink
    {
        public AOPAttribute() : base("AOP") { }
    
        /// <summary>
        /// 实现消息接收器接口
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next) => new MyAopHandler(next);
    }

    回到Calc类,给类和Methot加上特性标签:

    [AOP]
    public class Calc : ContextBoundObject
    {
        [AOPMethod]
        public int add(int a, int b)
        {
            return a + b;
        }
    }

    运行,效果如下:


    可以看到返回值已经被拦截修改处理过了

    试一下继承:

    [AOP]
    public class Calc : ContextBoundObject
    {
        [AOPMethod]
        public virtual int add(int a, int b)
        {
            return a + b;
        }
    }
    
    public class Calc2 : Calc
    {
        public override int add(int a, int b)
        {
            return a + b;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "";
            Console.WriteLine(new Calc2().add(1, 0));
            Console.WriteLine(new Calc2().add(2, 3));
            Console.WriteLine(new Calc2().add(1, 1));
            Console.ReadKey(true);
        }
    }

    运行效果:

    至此AOP的介绍结束,不过有一点很遗憾,无法修改参数,找了一下午资料无结果,如果谁知道怎么操作能否回复告知一下?

    原创文章,转载请注明来源. http://www.cnblogs.com/DragonStart/
     
     
  • 相关阅读:
    深入浅出了解OCR识别票据原理(Applying OCR Technology for Receipt Recognition)
    OCR技术浅探:基于深度学习和语言模型的印刷文字OCR系统
    Python 3.6.4 / win10 使用pip安装keras时遇到依赖的PyYAML安装出错
    简单http代理服务器搭建
    Socket之心跳包实现思路
    设计模式之访问者模式
    设计模式之责任链模式
    设计模式之策略者模式
    C#将.spl剥离成.emf文件格式
    设计模式之状态者模式
  • 原文地址:https://www.cnblogs.com/tianciliangen/p/8393005.html
Copyright © 2011-2022 走看看