能否通过Reflections实现泛型重写,用于开发功能完备的扩展日志?
结论
你给出的示例代码public class LoggingWrapper<T> : T不符合原生C#语法规则——C#不允许将泛型类型参数直接作为基类继承,因此这段代码无法直接通过编译,但你要的动态生成子类插入日志逻辑的需求完全可以通过反射体系实现,不需要拼接C#代码。
实现方案
你要的是典型的AOP方法拦截场景,用System.Reflection.Emit动态生成代理类即可实现,核心逻辑和你给出的示例设计思路完全匹配:
- 第一次处理某个类型
T时,通过ModuleBuilder动态创建一个继承自T的代理类 - 遍历
T的所有可重写虚方法,为每个方法生成重写逻辑,你设计的通用LoggingOutline方法可以直接复用,动态生成的代码会把基类方法的调用包装成委托传入该方法,实现前后插桩的效果 - 日志逻辑可以获取到全量运行信息:方法签名、参数列表、入参值、返回值、执行耗时、异常信息都可以在拦截逻辑中捕获,完全满足你的需求
性能优化方案
你提到的把反射相关数据缓存到内存字典的思路是完全正确的:
- 每个
T对应的代理类型只需要生成一次,生成后存入ConcurrentDictionary<Type, Type>缓存,后续创建实例时直接用缓存的代理类型创建即可,不需要重复执行反射遍历、IL生成逻辑 - 动态生成的代理类是原生IL代码,运行时性能和手写子类几乎没有差异,远高于每次调用时用反射
Invoke的性能
简化开发的替代方案
如果不想手动编写复杂的IL生成代码,可以直接用成熟的动态代理库(比如Castle DynamicProxy),这类库底层也是基于Reflection.Emit实现,已经封装好了方法拦截、参数获取、异常处理等边界逻辑,只需要实现自定义的拦截器写入日志逻辑即可,开发成本更低。
内容的提问来源于stack exchange,提问作者Kyoshiro Kokujou Obscuritas
相关产品推荐
相关产品推荐

