You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 16:48:06