如何使用Reflection.Emit隐藏现有方法并实现带日志功能的运行时代理类
如何使用Reflection.Emit隐藏现有方法并实现带日志功能的运行时代理类
没问题,我来一步步帮你实现这个带日志的运行时代理类,刚好你给的TestClass很适合当示例~
先提个关键小前提:如果要让代理类能重写基类的方法,基类的目标方法得标记为virtual(或者abstract),不然CLR不允许我们在子类里override它。所以我先把你的TestClass调整一下,给Hello方法加上virtual关键字:
public class TestClass { public virtual void Hello() { Console.WriteLine("Hello from TestClass!"); } }
接下来咱们就用Reflection.Emit来生成代理类,核心思路是:
- 动态创建一个继承自
TestClass的新类 - 对每个要重写的方法,先插入日志逻辑,再调用基类的原方法
下面是完整的实现代码,我会在关键地方加注释:
using System; using System.Reflection; using System.Reflection.Emit; class Program { static void Main() { // 1. 定义动态程序集和模块,用来承载我们的代理类 var assemblyName = new AssemblyName("DynamicProxyAssembly"); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicProxyModule"); // 2. 创建代理类,命名为TestClassProxy,继承自TestClass var typeBuilder = moduleBuilder.DefineType( "TestClassProxy", TypeAttributes.Public | TypeAttributes.Class, typeof(TestClass)); // 3. 获取基类的Hello方法,用来后续调用 var baseHelloMethod = typeof(TestClass).GetMethod("Hello", Type.EmptyTypes); // 4. 生成代理类的Hello方法,重写基类的Hello var methodBuilder = typeBuilder.DefineMethod( "Hello", MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard, null, Type.EmptyTypes); // 5. 编写IL指令,实现"先日志,再调用基类方法"的逻辑 var ilGenerator = methodBuilder.GetILGenerator(); // 先输出日志:Console.WriteLine("[LOG] 即将调用Hello方法...") ilGenerator.Emit(OpCodes.Ldstr, "[LOG] 即将调用Hello方法..."); var writeLineMethod = typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }); ilGenerator.Emit(OpCodes.Call, writeLineMethod); // 然后调用基类的Hello方法 ilGenerator.Emit(OpCodes.Ldarg_0); // 加载当前实例(this) ilGenerator.Emit(OpCodes.Call, baseHelloMethod); // 调用base.Hello() // 方法返回 ilGenerator.Emit(OpCodes.Ret); // 6. 完成代理类的创建,生成Type对象 var proxyType = typeBuilder.CreateType(); // 7. 测试一下:创建代理实例,调用Hello方法 var proxyInstance = (TestClass)Activator.CreateInstance(proxyType); proxyInstance.Hello(); } }
运行这段代码的话,你会看到输出是:
[LOG] 即将调用Hello方法...
Hello from TestClass!
完美符合你的需求吧?我再给你拆解几个关键部分:
- 动态程序集/模块/类的创建:这是Reflection.Emit的基础,所有动态类型都需要承载在程序集和模块里
- 方法重写的定义:必须保证代理类的方法签名和基类的
virtual方法完全一致,包括访问修饰符、返回值、参数 - IL指令的编写:这部分是核心,
Ldstr是加载字符串,Call是调用静态方法Console.WriteLine;Ldarg_0加载当前实例,然后Call基类的Hello方法,这样就完成了base调用
如果后续要处理更多方法,你可以把方法遍历的逻辑封装成一个方法,比如遍历基类的所有virtual方法,自动生成重写的逻辑,这样就不用一个个写了~
备注:内容来源于stack exchange,提问作者Jesoo
相关产品推荐
相关产品推荐

