C# 反射类的方法(普通反射+emit)

 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;
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值