在 C# 中,可以使用不同的方法调用内部或私有方法。下面分别介绍通过反射、MethodInfo.CreateDelegate、表达式(树)、动态方法(call)、动态方法(calli)这五种方法。

1. 通过反射方法

使用反射可以访问和调用内部或私有方法。

using System;
using System.Reflection; public class MyClass
{
private void MyPrivateMethod()
{
Console.WriteLine("调用了私有方法");
}
} class Program
{
static void Main()
{
MyClass myObject = new MyClass(); // 通过反射获取私有方法
MethodInfo methodInfo = typeof(MyClass).GetMethod("MyPrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance); // 调用私有方法
methodInfo.Invoke(myObject, null);
}
}

2. 使用 MethodInfo.CreateDelegate 方法

通过 MethodInfo.CreateDelegate 方法可以创建委托,然后调用私有方法。

using System;
using System.Reflection; public class MyClass
{
private void MyPrivateMethod()
{
Console.WriteLine("调用了私有方法");
}
} class Program
{
static void Main()
{
MyClass myObject = new MyClass(); // 通过反射获取私有方法
MethodInfo methodInfo = typeof(MyClass).GetMethod("MyPrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance); // 创建委托
Action action = (Action)Delegate.CreateDelegate(typeof(Action), myObject, methodInfo); // 调用私有方法
action();
}
}

3. 使用表达式(树)方法

通过表达式(树)可以创建动态方法,然后调用私有方法。

using System;
using System.Linq.Expressions; public class MyClass
{
private void MyPrivateMethod()
{
Console.WriteLine("调用了私有方法");
}
} class Program
{
static void Main()
{
MyClass myObject = new MyClass(); // 使用表达式创建动态方法
Action action = CreateDelegate<Action>(myObject, "MyPrivateMethod"); // 调用私有方法
action();
} // 使用表达式创建动态方法的通用方法
static TDelegate CreateDelegate<TDelegate>(object target, string methodName)
{
var methodInfo = target.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
var parameter = Expression.Parameter(typeof(object), "instance");
var call = Expression.Call(Expression.Convert(parameter, target.GetType()), methodInfo);
var lambda = Expression.Lambda<TDelegate>(call, parameter);
return lambda.Compile();
}
}

4. 使用动态方法(call)方法

使用动态方法可以调用私有方法。

using System;
using System.Reflection;
using System.Reflection.Emit; public class MyClass
{
private void MyPrivateMethod()
{
Console.WriteLine("调用了私有方法");
}
} class Program
{
static void Main()
{
MyClass myObject = new MyClass(); // 使用动态方法调用私有方法
CallPrivateMethod(myObject, "MyPrivateMethod");
} // 使用动态方法调用私有方法的通用方法
static void CallPrivateMethod(object target, string methodName)
{
var methodInfo = target.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); // 使用动态方法
var dynamicMethod = new DynamicMethod("CallMethod", null, new[] { typeof(object) }, target.GetType());
var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载第一个参数,即目标实例
ilGenerator.EmitCall(OpCodes.Call, methodInfo, null); // 调用私有方法
ilGenerator.Emit(OpCodes.Ret); // 返回
var action = (Action<object>)dynamicMethod.CreateDelegate(typeof(Action<object>)); // 调用私有方法
action(target);
}
}

5. 使用动态方法(calli)方法

使用动态方法(calli)可以调用私有方法。

using System;
using System.Reflection.Emit; public class MyClass
{
private void MyPrivateMethod()
{
Console.WriteLine("调用了私有方法");
}
} class Program
{
static void Main()
{
MyClass myObject = new MyClass(); // 使用动态方法(calli)调用私有方法
CallPrivateMethod(myObject, "MyPrivateMethod");
} // 使用动态方法(calli)调用私有方法的通用方法
static void CallPrivateMethod(object target, string methodName)
{
var methodInfo = target.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); // 使用动态方法(calli)
var dynamicMethod = new DynamicMethod("CallMethod", typeof(void), new[] { typeof(object) }, target.GetType());
var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载第一个参数,即目标实例
ilGenerator.EmitCalli(OpCodes.Call, methodInfo.CallingConvention, methodInfo.ReturnType, methodInfo.GetParameters().Select(p => p.ParameterType).ToArray(), null); // 调用私有方法
ilGenerator.Emit(OpCodes.Ret); // 返回
var action = (Action<object>)dynamicMethod.CreateDelegate(typeof(Action<object>)); // 调用私有方法
action(target);
}
}

以上五种方法都可以用于调用内部或私有方法,具体使用哪种方法取决于具体的场景和需求。

探秘C#中的秘密通道:五种引人注目的方法调用内部或私有方法的更多相关文章

  1. js中声明Number的五种方式

    转载自:http://www.jb51.net/article/34191.htm <!DOCTYPE html> <html> <head> <meta c ...

  2. 五种I/O 模式,select、epoll方法的理解,BIO、NIO、AIO理解 相关文章

    一.io方式 Linux网络编程 五种I/O 模式及select.epoll方法的理解 web优化必须了解的原理之I/o的五种模型和web的三种工作模式 五种I/O 模式——阻塞(默认IO模式),非阻 ...

  3. 面试中常问的五种IO模型和BIO,NIO,AIO

    一,五种IO模型: 一个IO操作可以分为两个步骤:发起IO请求和实际的IO操作例如:1.操作系统的一次写操作分为两步:第一步,将数据从用户空间拷贝到系统空间:第二步,从系统空间往网卡写.2.一次读操作 ...

  4. iOS开发中数组常用的五种遍历方式

    随着iOS的不断发展,apple也不断推出性能更高的数组遍历方式,下面将对熟悉的五种遍历方式进行列举. 首先定义一个数组,并获取数组长度 NSArray *array=@[",]; NSIn ...

  5. JavaScript中常见的十五种设计模式

    在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于“类”. 在JavaScript中并没有类这种概念,JS中的函数属于一等对象,在JS中定义一个对象非常简单(var obj = {}), ...

  6. webpack中,require的五种用法

    a.js: module.exports = function(x){ console.log(x); } 一,commonjs同步: var b = require('./a');b('你好')// ...

  7. Redis学习二 C#中如何进行这五种数据类型的操作

    我在网上找了好久,就是没有找到Redis和C#结合的书,都是和别的编程语言在一起鬼混. 简单的用C#实现向Redis中插入那我中类型的数据 首先需要到NuGet 里面下载 Redis IDatabas ...

  8. Redis 中可以存储的五种基本类型

    具体介绍 数字还是字符? String(字符串) 二进制安全 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M --- Hash(字典) 键值对集合,即编程语言中的Map类型 ...

  9. Java程序栈信息文件中的秘密(五)

    最近发现在使用jstack工具在导出Java应用的线程栈时有一个小小的窍门,比如Linux环境上有一个用户为appuser,假如以这个用户启动了一个Java进程B,如果想要导出进程B的线程栈,则必须切 ...

  10. NSNotification,NSNotificationCenter的使用、iOS中五种对象间传值的方式

    学习内容 NSNitification与NotificationCenter(通知与通知中心) 通知的使用 [[NSNotificationCenter defaultCenter]addObserv ...

随机推荐

  1. python 获取本周 ,上周,本月,上月,本季,上季,今年, 去年的第一天和最后一天

    import datetime from datetime import timedelta now = datetime.datetime.now()# 获取当前月的天数 month = 2days ...

  2. Codeforces 1257D - Yet Another Monster Killing Problem

    题意: 有\(n\)个怪物,每个怪物有攻击力\(a_i\)点:有\(m\)个英雄,每个英雄有攻击力\(p_i\)点,耐力\(s_{i}\)点. 怪物需要被依次杀死(按输入顺序). 每一天可以挑选一个英 ...

  3. jdk17下netty导致堆内存疯涨原因排查

    背景: 介绍 天网风控灵玑系统是基于内存计算实现的高吞吐低延迟在线计算服务,提供滑动或滚动窗口内的count.distinctCout.max.min.avg.sum.std及区间分布类的在线统计计算 ...

  4. Netty+WebSocket整合STOMP协议

    1.STOMP协议简介 常用的WebSocket协议定义了两种传输信息类型:文本信息和二进制信息.类型虽然被确定,但是他们的传输体是没有规定的,也就是说传输体可以自定义成什么样的数据格式都行,只要客户 ...

  5. python url中文转码_python实现转换url编码的方法

    python url中文转码_python实现转换url编码的方法 urllib.parse命令:url编码转换 >>> import urllib.parse >>&g ...

  6. 基于TOTP算法的Github两步验证2FA(双因子)机制Python3.10实现

    从今年(2023)三月份开始,Github开始强制用户开启两步验证2FA(双因子)登录验证,毫无疑问,是出于安全层面的考虑,毕竟Github账号一旦被盗,所有代码仓库都会毁于一旦,关于双因子登录的必要 ...

  7. Java新特性中的Preview功能如何运行和调试

    在每个Java新版本发布的特性中,都会包含一些Preview(预览)功能,这些功能主要用来给开发者体验并收集建议.所以,Preview阶段的功能并不是默认开启的. 如果想体验某个Java版本中的Pre ...

  8. The method dismissDialog(int) from the type Activity is deprecated

    The method showDialog(int) from the type Activity is deprecated in android?   up vote6down votefavor ...

  9. [GXYCTF 2019]BabyUpload

    看到题目是一个文件上传 就先随便传的东西试试,看有什么过滤之类的 上传一个一句话木马,提示后缀名不能为ph 随便上传了带有一句话木马的图片,发现上传成功,但这个图片不能直接利用,要先上传一个.htac ...

  10. 畅捷通T+任意文件上传(CNVD-2022-60632 )漏洞复现

    一.漏洞描述 022年8月29日和8月30日,畅捷通公司紧急发布安全补丁修复了畅捷通T+软件任意文件上传漏洞.未经身份认证的攻击者利用该漏洞,通过绕过系统鉴权,在特定配置环境下实现任意文件的上传,从而 ...