• 调用内部或私有方法的N种方法


    非公开的类型或者方法被“隐藏”在程序集内部,本就不希望从外部访问,但是有时候调用一个内部或者私有方法可能是唯一的“救命稻草”,这篇文章列出了几种具体的实现方式。以如下这个Foobar类型为例,它具有一个内部属性InternalValue,我们来看看有多少种方式可以从外部获取一个Foobar对象的InternalValue属性值。

    public class Foobar
    {
        internal int InternalValue => 123;
    }
    

    一、反射

    对于大部分人来说,最先想到的自然是“反射”,具体实现体现再如下所示的InternalValueAccessor类型的GetInternalValue方法中。但是我们都知道反射是一种并不高效的方式,对于需要频繁调用,我们一般不推荐使用。

    复制代码
    var foobar = new Foobar();
    Debug.Assert(InternalValueAccessor.GetInternalValue(foobar) == 123);
    
    public static class InternalValueAccessor
    {
        public static int GetInternalValue(Foobar foobar)
        {
            var propertyInfo = typeof(Foobar).GetProperty("InternalValue", BindingFlags.Instance | BindingFlags.NonPublic)!;
            return (int)propertyInfo.GetValue(foobar)!;
        }
    }
    
    复制代码

    二、MethodInfo.CreateDelegate方法

    要获得Foobar对象的InternalValue属性值(int类型),实际上需要一个Func类型的委托。由于返回值实际上是通过InternalValue属性的Get方法获得的,而表示方法的MethodInfo类型具有一个CreateDelegate方法,我们可以采用如下的方式利用InternalValue属性的Get方法来创建所需的Func委托。

    复制代码
    var foobar = new Foobar();
    Debug.Assert(InternalValueAccessor.GetInternalValue(foobar) == 123);
    
    public static class InternalValueAccessor
    {
        private static Funcint>? _getInternalValue;
        public static int GetInternalValue(Foobar foobar)=> (_getInternalValue??= CreateDelegate())(foobar);
        private static Funcint> CreateDelegate()
        {
            var methodInfo = typeof(Foobar).GetProperty("InternalValue", BindingFlags.Instance | BindingFlags.NonPublic)!.GetMethod!;
            return methodInfo.CreateDelegateint>>();
        }
    }
    
    复制代码

    三、表达式(树)

    一般来说,所有的反射解决方案都可以转换成基于表达式(树)的解决方案。我们需要的Func委托可以按照如下的方式,利用构建的表达式编译生成。

    复制代码
    public static class InternalValueAccessor
    {
        private static Funcint>? _getInternalValue;
        public static int GetInternalValue(Foobar foobar)=> (_getInternalValue??= CreateDelegate())(foobar);
        private static Funcint> CreateDelegate()
        {
            var methodInfo = typeof(Foobar).GetProperty("InternalValue", BindingFlags.Instance | BindingFlags.NonPublic)!.GetMethod!;
            var foobar = Expression.Parameter(typeof(Foobar), "foobar");
            var getValue = Expression.Call(foobar, methodInfo);
            return Expression.Lambdaint>>(getValue, foobar).Compile();
        }
    }
    
    复制代码

    四、动态方法(call)

    实际上表达式(树)是对IL代码的抽象表达,所以既然这样的问题自然可以利用IL Emit来解决。在如下的代码中,我们创建了一个DynamicMethod类型表示的动态方法,以IL Emit的方式利用IL指令Call完成了针对InternalValue属性的Get方法的调用。我们所需的Func委托最终由这个DynamicMethod对象创建而成。

    复制代码
    public static class InternalValueAccessor
    {
        private static Funcint>? _getInternalValue;
        public static int GetInternalValue(Foobar foobar) => (_getInternalValue ??= CreateDelegate())(foobar);
        private static Funcint> CreateDelegate()
        {
            var methodInfo = typeof(Foobar).GetProperty("InternalValue", BindingFlags.Instance | BindingFlags.NonPublic)!.GetMethod!;
            var method = new DynamicMethod("GetInternalValue", typeof(int), new Type[] { typeof(Foobar) });
            var il = method.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.EmitCall(OpCodes.Call, methodInfo, null);
            il.Emit(OpCodes.Ret);
            return method.CreateDelegateint>>();
        }
    }
    
    复制代码

    五、动态方法(calli)

    了解IL的朋友应该知道,方法调用涉及的IL治理有三个(Call、Callvir和Calli)。如果使用Calli指令,在完成针对参数的压栈之后,我们还需要执行Ldftn指令将方法指针压入栈中,最终执行Calli指令完成方法的执行。

    复制代码
    public static class InternalValueAccessor
    {
        private static Funcint>? _getInternalValue;
        public static int GetInternalValue(Foobar foobar) => (_getInternalValue ??= CreateDelegate())(foobar);
        private static Funcint> CreateDelegate()
        {
            var methodInfo = typeof(Foobar).GetProperty("InternalValue", BindingFlags.Instance | BindingFlags.NonPublic)!.GetMethod!;
            var method = new DynamicMethod("GetInternalValue", typeof(int), new Type[] { typeof(Foobar) });
            var il = method.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldftn, methodInfo);
            il.EmitCalli(OpCodes.Calli, CallingConventions.Standard, typeof(int), new Type[] { typeof(Foobar) }, null);
            il.Emit(OpCodes.Ret);
            return method.CreateDelegateint>>();
        }
    }
    
    复制代码
  • 相关阅读:
    华为ICT——第四章深度学习和积卷神经
    A_A02_001 CH340驱动安装
    金仓数据库KingbaseES备份与恢复工具手册(还原与恢复)
    一文搞懂机器学习!2024.6月最新!(附代码实现)
    Hadoop集群配置运行
    nigix安装以及遇到的问题
    04. 人工智能核心基础 - 导论(3)
    java类和对象——static成员与代码块
    VMware 安装 Centos7 超详细过程
    【Python深度学习】Python全栈体系(二十七)
  • 原文地址:https://www.cnblogs.com/artech/p/17547246.html