メソッドのattributeを確立し、任意のメソッドに置くことができ、メソッドエラー時の情報を自動的に記録することができ、tryを書く必要はありません.cacth. 【注意】aspではありません.NetMVCでは、通常の3層構造で書かれている特性です.
9207 ワード
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
TestA test = DynamicProxy.Create<TestA>();
int result = test.TestMethod(1, 2);
Console.WriteLine(result);
Console.WriteLine("done...");
Console.ReadLine();
}
}
public class TestA
{
[Log]
public virtual int TestMethod(int a, int b)
{
return a + b;
}
}
public class AspectContext
{
public object[] ParameterArgs { get; set; }
}
public abstract class AspectAttribute : Attribute
{
public abstract void BeforeInvoke(AspectContext cxt);
public abstract void AfterInvoke(AspectContext cxt);
}
public class LogAttribute : AspectAttribute
{
public override void BeforeInvoke(AspectContext cxt)
{
if (cxt != null && cxt.ParameterArgs != null)
{
foreach (object item in cxt.ParameterArgs)
Console.WriteLine(item);
}
Console.WriteLine("a");
}
public override void AfterInvoke(AspectContext cxt)
{
Console.WriteLine("b");
}
}
public class DynamicProxy
{
private static Dictionary<string, object> func_dic = new Dictionary<string, object>();
public static T Create<T>()
{
return Create<T>(typeof(T));
}
public static T Create<T>(Type srcType)
{
object obj = null;
if (!func_dic.TryGetValue(srcType.FullName, out obj))
{
lock (func_dic)
{
if (!func_dic.TryGetValue(srcType.FullName, out obj))
{
Type type = CreateProxyType(srcType);
obj = CreateFunc<T>(type);
func_dic.Add(srcType.FullName, obj);
}
}
}
//
Func<T> func = obj as Func<T>;
if (func == null)
throw new Exception("unknown exception");
return func();
}
//
private static Func<T> CreateFunc<T>(Type type)
{
DynamicMethod method = new DynamicMethod("", typeof(T), null);
var il = method.GetILGenerator();
ConstructorInfo info = type.GetConstructor(Type.EmptyTypes);
if (info == null) return null;
il.Emit(OpCodes.Newobj, info);
il.Emit(OpCodes.Ret);
return method.CreateDelegate(typeof(Func<T>)) as Func<T>;
}
private static Type CreateProxyType(Type srcType)
{
AssemblyName assemblyName = new AssemblyName(srcType.Name + "_Aop_Assmely");
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(srcType.Name + "_Aop_Module");
string typeName = srcType.Name + "_Aop";
TypeAttributes attr = TypeAttributes.Class | TypeAttributes.Public;
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, attr, srcType, Type.EmptyTypes);
MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
foreach (MethodInfo method in methods)
OverrideMethods(typeBuilder, method);
return typeBuilder.CreateType();
}
private static void OverrideMethods(TypeBuilder tb, MethodInfo method)
{
if (!method.IsPublic|| !method.IsVirtual || IsObjectMethod(method)) return;
Type[] paramTypes = GetParameterTypes(method);
MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual;
MethodBuilder mb = tb.DefineMethod(method.Name, attr, method.ReturnType, paramTypes);
LocalBuilder result = null;
ILGenerator il = mb.GetILGenerator();
bool is_void = method.ReturnType != typeof(void);
if (is_void == false)
result = il.DeclareLocal(method.ReturnType);
object[] attrs = method.GetCustomAttributes(typeof(AspectAttribute), false);
if (attrs != null)
{
// object[]
CreateLocalParameterArr(il, paramTypes);
// AspectContext
Type ctxType = typeof(AspectContext);
ConstructorInfo info = ctxType.GetConstructor(Type.EmptyTypes);
var ctx = il.DeclareLocal(ctxType);
il.Emit(OpCodes.Newobj, info);
il.Emit(OpCodes.Stloc, ctx);
// AspectContext ParameterArgs
var propMethod = ctxType.GetMethod("set_ParameterArgs");
il.Emit(OpCodes.Ldloc, ctx);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Call, propMethod);
int m = attrs.Length;
LocalBuilder[] lbs = new LocalBuilder[m];
MethodInfo[] endInvokeMethods = new MethodInfo[m];
// , BeforeInvoke
for (int i = 0; i < m; i++)
{
var tmpType = attrs[i].GetType();
var aspect = il.DeclareLocal(tmpType);
ConstructorInfo tmpInfo = tmpType.GetConstructor(Type.EmptyTypes);
il.Emit(OpCodes.Newobj, tmpInfo);
il.Emit(OpCodes.Stloc, aspect);
var before_invoke_method = tmpType.GetMethod("BeforeInvoke");
endInvokeMethods[i] = tmpType.GetMethod("AfterInvoke");
il.Emit(OpCodes.Ldloc, aspect);
il.Emit(OpCodes.Ldloc, ctx);
il.Emit(OpCodes.Callvirt, before_invoke_method);
il.Emit(OpCodes.Nop);
lbs[i] = aspect;
}
// ,
for (int i = 0; i <= paramTypes.Length; i++)
il.Emit(OpCodes.Ldarg, i);
//
il.Emit(OpCodes.Call, method);
// ,
if (is_void == false)
il.Emit(OpCodes.Stloc, result);
// AfterInvoke
for (int i = 0; i < m; i++)
{
il.Emit(OpCodes.Ldloc, lbs[i]);
il.Emit(OpCodes.Ldloc, ctx);
il.Emit(OpCodes.Callvirt, endInvokeMethods[i]);
il.Emit(OpCodes.Nop);
}
// ,
if (is_void == false)
il.Emit(OpCodes.Ldloc, result);
//
il.Emit(OpCodes.Ret);
}
}
private static void CreateLocalParameterArr(ILGenerator il, Type[] paramTypes)
{
il.DeclareLocal(typeof(object[]));
il.Emit(OpCodes.Ldc_I4, paramTypes.Length);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Stloc_0);
for (int i = 0; i < paramTypes.Length; i++)
{
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldarg, i + 1);
if (paramTypes[i].IsValueType)
il.Emit(OpCodes.Box, paramTypes[i]);
il.Emit(OpCodes.Stelem_Ref);
}
}
private static Type[] GetParameterTypes(MethodInfo method)
{
var paramInfos = method.GetParameters();
int len = paramInfos.Length;
Type[] paramTypes = new Type[len];
for (int i = 0; i < len; i++)
paramTypes[i] = paramInfos[i].ParameterType;
return paramTypes;
}
// Object
private static bool IsObjectMethod(MethodInfo info)
{
string[] arr = new string[] { "ToString", "GetType", "GetHashCode", "Equals" };
return arr.Contains(info.Name);
}
}
}
例:AttrbuteTest//この特性はメソッドの異常をキャプチャし、ログpublic void Test(){string str="test";int i=int.Parse(str);
原文出典:http://q.cnblogs.com/q/57373/