dispatchproxy 是 .net core 2.1+ 和 .net 5+ 内置的仅支持接口代理的轻量级动态代理基类,需继承并重写 invoke 方法,通过 create 创建代理实例,且必须手动注入目标对象,不支持类代理、aot 编译及 .net framework。

DispatchProxy 是什么,能不能直接用
DispatchProxy 是 .NET Core 2.1+ 和 .NET 5+ 内置的轻量级动态代理基类,用于在运行时生成代理类型,拦截方法调用。它不依赖第三方库(如 Castle.Core),也不需要 System.Reflection.Emit 的复杂操作,但**仅支持接口代理**——不能代理类、不能代理无接口的类型。
常见误用:试图让 DispatchProxy 代理一个普通类(比如 class UserService),结果抛出 NotSupportedException: Cannot proxy a non-Interface type。这是设计限制,不是 bug。
如何正确创建并使用 DispatchProxy 代理
必须定义接口,并让代理类继承 DispatchProxy,重写 Invoke 方法。代理实例通过 DispatchProxy.Create<t>()</t> 创建,其中 T 必须是接口类型。
- 代理类需继承
DispatchProxy,且声明为public(否则Create会失败) -
Invoke方法里可访问target(即被代理的真实实现)、method(被调用的方法信息)、args(参数数组) - 若未手动调用
target?.GetType().GetMethod(...).Invoke(...),方法不会真正执行——DispatchProxy不自动转发,必须显式处理
示例:
public interface ICalculator { int Add(int a, int b); } public class LoggingProxy : DispatchProxy { private ICalculator _target; protected override object Invoke(MethodInfo targetMethod, object[] args) { Console.WriteLine($"Calling {targetMethod.Name} with {string.Join(", ", args)}"); return targetMethod.Invoke(_target, args); // 必须手动转发 } } // 使用: var proxy = DispatchProxy.Create<ICalculator, LoggingProxy>(); // 注意:proxy 此时还不是可用对象,需设置内部 target var realImpl = new CalculatorImpl(); typeof(LoggingProxy).GetField("_target", BindingFlags.NonPublic | BindingFlags.Instance) .SetValue(proxy, realImpl);
为什么代理对象调用后没日志、也没报错
最常见原因:没给代理类的私有字段(如 _target)赋值,或字段名/访问权限不对。因为 DispatchProxy.Create 只生成代理实例,不初始化其内部状态;它也不提供构造函数注入机制。
- 字段名必须完全匹配(大小写敏感),且要用
BindingFlags.NonPublic | BindingFlags.Instance - 如果代理类用了
private readonly字段,反射无法赋值,得改成private - .NET 6+ 中若启用了 AOT 编译(如发布为 native AOT),
DispatchProxy会被禁用,运行时报PlatformNotSupportedException - 泛型接口(如
IRepository<t></t>)可以代理,但Create<irepository>, Proxy>()</irepository>中的User必须是具体类型,不能是泛型参数
DispatchProxy 的性能和替代方案对比
DispatchProxy 的调用开销比直接调用高约 3–5 倍(取决于方法复杂度),主要来自反射调用 MethodInfo.Invoke 和装箱。它适合低频、调试、AOP 日志等场景,不适合高频核心路径(如游戏循环、高频数学计算)。
- 想避免反射调用?可改用
Expression.Lambda或源生成器(Source Generator)预生成代理,但开发成本显著上升 - 需要代理类而非接口?只能换方案:Castle.Core(需 NuGet)、DynamicProxy(同属 Castle)、或 .NET 8 的
System.Runtime.CompilerServices.CallInterceptors(实验性,仅限特定平台) - 注意:.NET Framework 不支持
DispatchProxy,它只存在于System.Reflection.DispatchProxy命名空间中,且最低要求 .NET Core 2.1
真正麻烦的不是怎么写代理,而是怎么安全地把真实实现塞进代理实例里——字段名拼错、访问权限漏设、AOT 环境下静默失效,这些才是线上出问题的高发点。