public static class MethodProxyEx
{
private static readonly ConcurrentDictionary<string, Delegate> _methodCache;
static MethodProxyEx()
{
_methodCache = new ConcurrentDictionary<string, Delegate>();
}
public static OutType GetMethodProxy<OutType>(this object target, string methodName) where OutType : Delegate
=> (OutType)target.GetMethodDelegate<OutType>(methodName);
public static Delegate GetMethodDelegate<OutType>(this object target, string methodName) where OutType : Delegate
{
Type type = target.GetType();
string key = type.CreationKey<OutType>(methodName);
return _methodCache.GetOrAdd(key, k => type.MethodProxy<OutType>(methodName, target));
}
public static OutType GetMethodProxy<OutType>(this Type type, string methodName) where OutType : Delegate
=> (OutType)type.GetMethodDelegate<OutType>(methodName);
public static Delegate GetMethodDelegate<OutType>(this Type type, string methodName) where OutType : Delegate
{
string key = type.CreationKey<OutType>(methodName);
return _methodCache.GetOrAdd(key, k => type.MethodProxy<OutType>(methodName));
}
#region emit反射
private static Delegate MethodProxy<OutType>(this Type type, string methodName, object target)
=> type.MethodProxyDelegate<OutType>(methodName, target);
private static Delegate MethodProxy<OutType>(this Type type, string methodName)
=> type.MethodProxyDelegate<OutType>(methodName, null);
private static Delegate MethodProxyDelegate<OutType>(this Type type, string methodName, object target)
{
Type outType = typeof(OutType);
MethodInfo outMethod = outType.GetMethod("Invoke");
ParameterInfo[] parameters = outMethod.GetParameters();
Type[] parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
// 包括非公有方法和静态方法
var methodInfo = type.GetMethod(
methodName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
null, parameterTypes, null);
if (methodInfo == null)
throw new InvalidOperationException(string.Format("Method '{0}' not found in {1}.", methodName, type.FullName));
// 为动态方法添加target类型
parameterTypes = new Type[] { type }.Concat(parameterTypes).ToArray();
var dynamicMethod = new DynamicMethod(
string.Format("Dynamic{0}Proxy", methodName),
outMethod.ReturnType,
parameterTypes,
type.Module,
skipVisibility: true);
var ilGenerator = dynamicMethod.GetILGenerator();
if (!methodInfo.IsStatic)
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载target实例
for (int i = 1; i < parameterTypes.Length; i++)
{
ilGenerator.Emit(OpCodes.Ldarg, i); // 加载参数,参数索引从1开始(因为0是target实例)
}
ilGenerator.Emit(methodInfo.IsStatic ? OpCodes.Call : OpCodes.Callvirt, methodInfo);
ilGenerator.Emit(OpCodes.Ret); // 返回
// 创建并返回委托
Delegate @delegate = dynamicMethod.CreateDelegate(outType, target);
return @delegate;
}
#endregion
#region 普通反射
private static Delegate MethodProxy2<OutType>(this Type type, string methodName, object target)
=> type.MethodProxy2Delegate<OutType>(methodName, null);
private static Delegate MethodProxy2<OutType>(this Type type, string methodName)
=> type.MethodProxy2Delegate<OutType>(methodName, null);
private static Delegate MethodProxy2Delegate<OutType>(this Type type, string methodName, object target)
{
Type outType = typeof(OutType);
MethodInfo outMethod = outType.GetMethod("Invoke");
var parameterTypes = outMethod.GetParameters().Select(p => p.ParameterType).ToArray();
var methodInfo = type.GetMethod(
methodName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static,
null, parameterTypes, null);
if (methodInfo == null)
throw new InvalidOperationException(string.Format("Method '{0}' not found in {1}.", methodName, type.Name));
// 使用反射创建委托
return Delegate.CreateDelegate(outType, target, methodInfo);
}
#endregion
private static string CreationKey<OutType>(this Type type, string methodName)
{
Type outType = typeof(OutType);
// 不保证唯一
//string key = string.Format("{0}-{1}", type.GetHashCode(), outType.GetHashCode());
MethodInfo outMethod = outType.GetMethod("Invoke");
string key = string.Format("{0}-{1}-{2}", type.FullName, methodName, string.Join(",", outType.GetMethod("Invoke").GetParameters().Select(t => t.ParameterType.FullName)));
return key;
}
}
C# 反射类的方法(普通反射+emit)
于 2024-12-11 16:15:19 首次发布