方法级AOP: 又一个补丁
当前版本的地址如下:
https://files.cnblogs.com/guaiguai/FuncTest.zip
这个小例子可以看作方法级的AOP, 包里是一种实现方法, 利用了新的Expression, 比起生成动态代理类的做法那是清凉多了(当然, 也可以以这个为基础, 组合出复杂的方式,或者和生成动态代理类互补), 使用起来也灵活, 就是表达方式有点丑, 比如这样:
string c = "fuck";

MethodCall.Extract(() => bar.DoSomething(c)).Invoke();
有返回时(上面的DoSomething是实例的方法, 下面这个是静态方法):
int a = 3;
int b = 4;

List<int> list1 = MethodCall.Extract(() => Foo.DoSomething(a, "hello", b)).FromCache().Invoke();
其中使用“()=>”这样的表达式写法是为了提取足够的信息, 包括方法、 实例和参数, FromCache这样的东西当然要自己扩展啦, 上面的包里有一个简单的例子; 而Invoke则触发它执行。
其实FromCache这样的Extension并不好, 如果这样扩展,那么使用时“FromCache().Log().CheckAccess().....Invoke()”这样臃肿的写法就会大量重复; 这里我有一个重构的方式, 不过想先听听大家的意见, 所以暂时卖个关子。
上面提到的重构,还有帮助组合的辅助设施,包括搭配使用的动态代理类生成器, 我暂时都不打算实现, 做全了工作量比较大, 同时很可能就又成了一个框架了。 最近一段时间,我个人对框架式的做法比较谨慎, 拿出这个轻薄短小的例子, 也是想先讨论一下。
这是跟老赵还有脑袋讨论的成果,其中Emit生成方法快速调用部分是1、2年前参照卢彦的例子改的(可以单独用到其它场合,不保证没有Bug哦)。脑袋其实不赞成用Emit干活的方式, 我个人同意脑袋的意见; 不过呢, 这个东西也不是完全没用, 放出来抛砖引玉吧。
这个解法的关键代码, 脑袋的“蛮力”解法, 以及这种解法和“蛮力”法之间的区别, 等时间多点一并分析。这个实现和其中的例子都比较草, 基本还是试验级别的,如果有问题可以给我留言。
Update:
做了几个测试, 发现对表达式可能出现的情况估计不足, 很多情况没有处理; 同时取表达式中的值使用了FieldInfo和PropertyInfo的GetValue, 如果执行次数很多, 效率不行(这个问题好解决, 也是用Emit生成快速调用的方法即可)。 大家暂时当例子看看, 我稍后会更新这些代码, 上面的包已经更新了一次, 添加了UnaryExpression作为参数的方法的支持:
jl_Block bundle = MethodCall.Extract(
() => dc.jl_Blocks.Single(
(x) => x.ForumID == s.SectionID)
).FromCache().Invoke();
看起来是不是稍微有点变态了? =) 事实上我觉得这样写还是不够爽, 如果变成这样:
jl_Block bundle = Cache(
() => dc.jl_Blocks.Single(
(x) => x.ForumID == s.SectionID)
)();

//或者这样

jl_Block bundle = Cache(
() => dc.jl_Blocks.Single
)((x) => x.ForumID == s.SectionID);
也许比较令人满意, 你觉得上面哪种比较好看呢?大家帮忙想想还有什么比较爽的写法吧。当然, 能不能实现就是另外一码事了 :P 另外, 已经照顾到的情况实际上还是很少的,当前版本肯定还有很多其它问题, 有闲趣的人不妨看看, 和我一起改进。
https://files.cnblogs.com/guaiguai/FuncTest.zip
这个小例子可以看作方法级的AOP, 包里是一种实现方法, 利用了新的Expression, 比起生成动态代理类的做法那是清凉多了(当然, 也可以以这个为基础, 组合出复杂的方式,或者和生成动态代理类互补), 使用起来也灵活, 就是表达方式有点丑, 比如这样:



有返回时(上面的DoSomething是实例的方法, 下面这个是静态方法):




其中使用“()=>”这样的表达式写法是为了提取足够的信息, 包括方法、 实例和参数, FromCache这样的东西当然要自己扩展啦, 上面的包里有一个简单的例子; 而Invoke则触发它执行。
其实FromCache这样的Extension并不好, 如果这样扩展,那么使用时“FromCache().Log().CheckAccess().....Invoke()”这样臃肿的写法就会大量重复; 这里我有一个重构的方式, 不过想先听听大家的意见, 所以暂时卖个关子。
上面提到的重构,还有帮助组合的辅助设施,包括搭配使用的动态代理类生成器, 我暂时都不打算实现, 做全了工作量比较大, 同时很可能就又成了一个框架了。 最近一段时间,我个人对框架式的做法比较谨慎, 拿出这个轻薄短小的例子, 也是想先讨论一下。
这是跟老赵还有脑袋讨论的成果,其中Emit生成方法快速调用部分是1、2年前参照卢彦的例子改的(可以单独用到其它场合,不保证没有Bug哦)。脑袋其实不赞成用Emit干活的方式, 我个人同意脑袋的意见; 不过呢, 这个东西也不是完全没用, 放出来抛砖引玉吧。
这个解法的关键代码, 脑袋的“蛮力”解法, 以及这种解法和“蛮力”法之间的区别, 等时间多点一并分析。这个实现和其中的例子都比较草, 基本还是试验级别的,如果有问题可以给我留言。
Update:
做了几个测试, 发现对表达式可能出现的情况估计不足, 很多情况没有处理; 同时取表达式中的值使用了FieldInfo和PropertyInfo的GetValue, 如果执行次数很多, 效率不行(这个问题好解决, 也是用Emit生成快速调用的方法即可)。 大家暂时当例子看看, 我稍后会更新这些代码, 上面的包已经更新了一次, 添加了UnaryExpression作为参数的方法的支持:




看起来是不是稍微有点变态了? =) 事实上我觉得这样写还是不够爽, 如果变成这样:










也许比较令人满意, 你觉得上面哪种比较好看呢?大家帮忙想想还有什么比较爽的写法吧。当然, 能不能实现就是另外一码事了 :P 另外, 已经照顾到的情况实际上还是很少的,当前版本肯定还有很多其它问题, 有闲趣的人不妨看看, 和我一起改进。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器