zoukankan      html  css  js  c++  java
  • 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的介绍结束,不过有一点很遗憾,无法修改参数,找了一下午资料无结果,如果谁知道怎么操作能否回复告知一下?

  • 相关阅读:
    广搜 BFS()
    最短路-A
    DFS-C
    codeforces contest
    小技巧
    将博客搬至CSDN
    建树
    codeforces gym102411 Equidistant(图论+乱搞)
    codeforces 1250N wires(简单图论)
    Splay 树
  • 原文地址:https://www.cnblogs.com/DragonStart/p/7744202.html
Copyright © 2011-2022 走看看