using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace SHJX.Service.Common.Proxy
{
///
/// 代理类
///
public static class Proxy
{
public static object NewProxyInstance(Type realObj, object proxyObj)
{
string nameOfAssembly = realObj.Name + "ProxyAssembly";
string nameOfModule = realObj.Name + "ProxyModule";
string nameOfType = realObj.Name + "Proxy";
var assemblyName = new AssemblyName(nameOfAssembly);
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assembly.DefineDynamicModule(nameOfModule);
var typeBuilder = moduleBuilder.DefineType(nameOfType, TypeAttributes.Public | TypeAttributes.NotPublic, realObj);
InjectInterceptor(realObj, typeBuilder, proxyObj);
var t = typeBuilder.CreateType();
return Activator.CreateInstance(t);
}
private static void InjectInterceptor(Type type, TypeBuilder typeBuilder, object proxy)
{
var fieldInterceptor = typeBuilder.DefineField("_interceptor", proxy.GetType(), FieldAttributes.Private);
var constructorBuilder =
typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
var ilOfCtor = constructorBuilder.GetILGenerator();
ilOfCtor.Emit(OpCodes.Ldarg_0);
ilOfCtor.Emit(OpCodes.Newobj, proxy.GetType().GetConstructor(Array.Empty())!);
ilOfCtor.Emit(OpCodes.Stfld, fieldInterceptor);
ilOfCtor.Emit(OpCodes.Ret);
var methodsOfType = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
foreach (var method in methodsOfType)
{
var methodParameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
var attr = MethodAttributes.Public | MethodAttributes.Virtual;
var methodBuilder = typeBuilder.DefineMethod(method.Name, attr, CallingConventions.Standard,
method.ReturnType, methodParameterTypes);
var ilOfMethod = methodBuilder.GetILGenerator();
ilOfMethod.Emit(OpCodes.Ldarg_0);
ilOfMethod.Emit(OpCodes.Ldfld, fieldInterceptor);
ilOfMethod.Emit(OpCodes.Newobj, type.GetConstructor(Array.Empty())!);
ilOfMethod.Emit(OpCodes.Ldstr, method.Name);
var parameters = ilOfMethod.DeclareLocal(typeof(object[]));
ilOfMethod.Emit(OpCodes.Ldc_I4, methodParameterTypes.Length);
ilOfMethod.Emit(OpCodes.Newarr, typeof(object));
ilOfMethod.Emit(OpCodes.Stloc, parameters);
for (var j = 0; j < methodParameterTypes.Length; j++)
{
ilOfMethod.Emit(OpCodes.Ldloc, parameters);
ilOfMethod.Emit(OpCodes.Ldc_I4, j);
ilOfMethod.Emit(OpCodes.Ldarg, j + 1);
ilOfMethod.Emit(OpCodes.Stelem_Ref);
}
ilOfMethod.Emit(OpCodes.Ldloc, parameters);
ilOfMethod.Emit(OpCodes.Callvirt, proxy.GetType().GetMethod("Invoke")!);
if (method.ReturnType == typeof(void))
{
ilOfMethod.Emit(OpCodes.Pop);
}
ilOfMethod.Emit(OpCodes.Ret);
}
}
}
}