有時候我們需要在代碼中對方法調用進行攔截,並修改參數和返回值,這種操作叫做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的介紹結束,不過有一點很遺憾,無法修改參數,找了一下午資料無結果,如果誰知道怎么操作能否回復告知一下?