轉,C#動態代理實現AOP


自: 

https://blog.csdn.net/weixin_37390956/article/details/79947976

搬磚,

--------------------
/// <summary>
/// 創建動態代理方法
/// </summary>
/// <param name="typeBuilder">類型構造器</param>
/// <param name="method">方法元數據</param>
/// <param name="realObjectField">實際對象</param>
/// <param name="aspectFields">切面</param>
private static void EmitMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder realObjectField, List<AspectField> aspectFields)
{
//參數列表
var parameters = method.GetParameters();
//動態實例
var emitter = Sigil.NonGeneric.Emit.BuildInstanceMethod(method.ReturnType, parameters.Select(i => i.ParameterType).ToArray(), typeBuilder, method.Name, MethodAttributes.Public | MethodAttributes.Virtual);

//label base
var lbCallBase = emitter.DefineLabel();
//label return
var lbReturn = emitter.DefineLabel();

//方法上下文
var methodContextLocal = emitter.DeclareLocal(typeof(MethodContext));
//返回
var returnLocal = method.ReturnType != typeof(void) ? emitter.DeclareLocal(method.ReturnType) : null;
//本地存儲
var objArrayLocal = emitter.DeclareLocal(typeof(object[]));
//異常
var exceptionLocal = emitter.DeclareLocal<Exception>();
//切面列表
var aspects = method.GetCustomAttributes(typeof(AspectAttribute), false).Cast<AspectAttribute>().Concat(AspectFactory.GlobalAspects).ToList();
//是否包含異常切面
bool hasException = aspects.Any(i => i.GetType().GetMethod("ExceptionFilter").DeclaringType != typeof(AspectAttribute));
//異常捕捉塊
Sigil.ExceptionBlock tryBlock = null;
//方法名
string methodName = method.Name;
if (aspects.Any())
{
//給參數分配內存
emitter
.LoadConstant(parameters.Length)
.NewArray<object>()
.StoreLocal(objArrayLocal); // var parameters = new object[parameters.Length];

//給參數填充實際值
for (int i = 0; i < parameters.Length; i++)
{
emitter
.LoadLocal(objArrayLocal)
.LoadConstant(i)
.LoadArgument((ushort)(i + 1))
.Box(parameters[i].ParameterType, true)
.StoreElement<object>(); // parameters[i] = paramN;
}

//通過使用該方法的內部元數據表示形式 (句柄) 獲取方法的信息
emitter
.LoadConstant(method)
.Call(typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) }))
.CastClass<MethodInfo>() // methodof(Method)

//加載真實方法對象
.LoadArgument(0)
.LoadField(realObjectField) // this.realObject

//加載自定義的上下文
.LoadLocal(objArrayLocal)
.Call(typeof(ProxyBase).GetMethod("GetMethodContext", BindingFlags.Static | BindingFlags.NonPublic))
.StoreLocal(methodContextLocal); // methodContextLocal = GetMethodContext(methodof(Method), this.realObject, parameters
}

var currentMethodAspects = new List<AspectField>();
//根據切面的優先級排序
foreach (var aspect in aspects.OrderBy(i => i.EnterPriority))
{
//創建切面
var field = typeBuilder.DefineField("aspectField_" + Guid.NewGuid(), typeof(AspectAttribute), FieldAttributes.Static | FieldAttributes.Private);
aspectFields.Add(new AspectField { Aspect = aspect, Field = field });
currentMethodAspects.Add(new AspectField { Aspect = aspect, Field = field });

//調用切面前處理
emitter
.LoadField(field)
.LoadLocal(methodContextLocal)
.CallVirtual(typeof(AspectAttribute).GetMethod(GetName(aspect.MethodEnter), BindingFlags.Instance | BindingFlags.Public));

//如果方法有返回則試圖獲取 返回值 返回如果不為空則標志lbreturn 直接返回結束
if (method.ReturnType != typeof(void))
{
emitter
.LoadLocal(methodContextLocal)
.Call(typeof(MethodContext).GetProperty("ReturnValue").GetGetMethod())
.BranchIfTrue(lbReturn);
}
}

//Chama o método base 標記調用父方法
emitter.MarkLabel(lbCallBase);

//如果包含異常捕捉切面則添加一個trycatch塊
if (hasException)
tryBlock = emitter.BeginExceptionBlock();

if (aspects.Any() && method.ReturnType != typeof(void)) //Armazena o objeto retornado no ReturnValue caso haja aspectos
emitter.LoadLocal(methodContextLocal);

emitter
.LoadArgument(0)
.LoadField(realObjectField);
for (int i = 0; i < parameters.Length; i++)
emitter.LoadArgument((ushort)(i + 1));
//調用實際的方法
emitter.CallVirtual(method); //realObject.Method(parameters...);
//保存返回值
if (method.ReturnType != typeof(void))
emitter.StoreLocal(returnLocal);


//Armazena o objeto retornado no ReturnValue caso haja aspectos
//設置methodcontext里的返回值
if (method.ReturnType != typeof(void) && aspects.Any())
{
emitter
.LoadLocal(returnLocal)
.Box(method.ReturnType, true)
.Call(typeof(MethodContext).GetProperty("ReturnValue").GetSetMethod());
}

//開始調用切面里面的異常處理
if (hasException)
{
var catchBlock = emitter.BeginCatchBlock<Exception>(tryBlock);
emitter.StoreLocal(exceptionLocal);

foreach (var aspect in currentMethodAspects.Where(i => i.Aspect.GetType().GetMethod("ExceptionFilter").DeclaringType != typeof(AspectAttribute)))
emitter
.LoadField(aspect.Field)
.LoadLocal(methodContextLocal)
.LoadLocal(exceptionLocal)
.CallVirtual(typeof(AspectAttribute).GetMethod("ExceptionFilter", BindingFlags.Instance | BindingFlags.Public));
//切面異常處理結束之后重新拋出異常 不影響后續流程
emitter
.ReThrow()
.EndCatchBlock(catchBlock)
.EndExceptionBlock(tryBlock);
}

//循環按照優先級調用切面后處理
emitter.MarkLabel(lbReturn);
foreach (var aspect in currentMethodAspects.OrderBy(i => i.Aspect.ExitPriority))
{
emitter
.LoadField(aspect.Field)
.LoadLocal(methodContextLocal)
.CallVirtual(typeof(AspectAttribute).GetMethod(GetName(aspect.Aspect.MethodExit), BindingFlags.Instance | BindingFlags.Public));
}
//存儲返回值
if (method.ReturnType != typeof(void))
{
if (aspects.Any())
{
emitter
.LoadLocal(methodContextLocal)
.Call(typeof(MethodContext).GetProperty("ReturnValue").GetGetMethod())
.UnboxAny(method.ReturnType, true)
.StoreLocal(returnLocal);

}

if (method.ReturnType != typeof(void))
emitter.LoadLocal(returnLocal);
}
//返回
emitter.Return();
//生成代理方法
var newMethod = emitter.CreateMethod();
typeBuilder.DefineMethodOverride(newMethod, method);
}
---------------------
作者:我們生活在果殼中
來源:CSDN
原文:https://blog.csdn.net/weixin_37390956/article/details/79947976

----------------------

其他參考,,,AOP從靜態代理到動態代理(Emit實現)詳解   (這篇不錯):  https://www.jb51.net/article/147526.htm


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM