怪怪 | Nothing, Everything
"有过一个发疯的时刻,有感觉的钢琴以为它是世界上仅有的一架钢琴,宇宙的全部和谐都发生在它身上." - 狄德罗
随笔 - 104, 文章 - 3, 评论 - 2004, 引用 - 44
数据加载中……
方法级AOP: 又一个补丁
当前版本的地址如下:
http://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 另外, 已经照顾到的情况实际上还是很少的,当前版本肯定还有很多其它问题, 有闲趣的人不妨看看, 和我一起改进。
posted on 2008-06-12 23:54
怪怪
阅读(4521)
评论(19)
编辑
收藏
评论
#1楼
回复
引用
查看
怪怪也写技术了?很少见啊,呵呵
最近也看了些AOP方面的东西,不过像你这种实现方式还没见到过,
看了一些AOP编程后怎么发现rails里面的before_filter,after_filter就是perfect的AOP
2008-06-13 00:27 |
横刀天笑
#2楼
回复
引用
查看
加一句:我居然是沙发,呵呵
2008-06-13 00:27 |
横刀天笑
#3楼
[
楼主
]
回复
引用
查看
@横刀天笑
现在居然还有人醒着... 你说的对, 虽然我不了解ruby, 不过动态语言玩这个, 要自然多了。
其实我感觉自己不适合写这类文章, 而且写着也不来劲; 看看干瘪瘪的文章内容就知道了。
更别提涉及的一些概念我本人是有抵触情绪的,不过用着C#也没办法不是。
毕竟折腾了好几个小时, 扔了就白费了, 拿出来看看谁正好用的着, 也许还能发挥点余热~
2008-06-13 00:34 |
怪怪
#4楼
回复
引用
查看
除了代码看着比较。。。以外
思路还是不错 个人愚钝 觉得还是一种动态代理的实现
Emit生成听着就有点害怕,不过和原来的实现方式做一下比较说不定会有惊喜哦~呵呵~
BTW: 怪怪辛苦啊,这么晚还在写
2008-06-13 00:35 |
xwang
#5楼
[
楼主
]
回复
引用
查看
@xwang
确实我文中"动态代理"的说法, 不是完全妥当的,因为我这个最终也包装了一层; 只是这个仅仅在方法级别包装(也许是最小的粒度了), 因此可以零散的、 自由的使用; 更合适的说法, 应该是跟动态代理类相较而言。
我更新一下。
何着夜猫子这么多...
2008-06-13 00:45 |
怪怪
#6楼
回复
引用
查看
c#3.0還沒看熟
飄過...
2008-06-13 08:33 |
小生
#7楼
回复
引用
查看
string c = "fuck";
嘿嘿
2008-06-13 08:51 |
xiao_p
#8楼
回复
引用
查看
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);
这样的语句,
第一次看见是在老赵发的“你善于使用匿名函数”的时候,当时就有种怪怪的感觉,好大一堆东西放在一起乱七八糟的。
不过,后来稍微看了些函数编程的东西,发现慢慢有点适应这种表达方式了。
2008-06-13 08:52 |
xiao_p
#9楼
回复
引用
List<int> list1 = MethodCall.Extract(() => Foo.DoSomething(a, "hello", b)).FromCache().Invoke();
其实这种就如双鱼座所说了,这并不是aop.这已经是非常有目的地调用所需功能.
aop对我个人而言是具备对原来代码无入侵性(特别是代码的编写方式),这里显然满足不了要求.
其实用Emit感觉不错,因为我们不需要完全用emit完成所有aop处理的功能,只实现切入调用就可以了,可惜现在无法找到比较纯正的aop实现.
如果MS提供methodbody的il修改就好了,而这个修改允许在jit之前进行,只生效于当前appdomain
2008-06-13 09:12 |
henryfan [未注册用户]
#10楼
回复
引用
查看
以下是我的实现,不过可惜的是现在只支持接口实现这个规则.
[NClay.Services.Aspect(typeof(Foo)]
public List<int> DoSomething(int a,string name,int b)
{
List<int> value = FromCache();
if(value== null)
value = MethodContext.Invoke<List<int>>(a,name,b);
return value
}
2008-06-13 09:32 |
henry
#11楼
[
楼主
]
回复
引用
查看
@henryfan
嗯, 你说的有道理, 不过, 我非要把FromCache()写在那里吗? :) 我这个例子简单到只是提供一个思路, 如何满足需求, 就看咱们怎么用啦。
至于无侵入, 在C#下,对DoSomething的实现完全无侵入就很不错了, 总不会要求virtual什么的。 调用方法的形式稍微产生点变化,我觉得在很多场景下,是个合理的交换。
当然动态代理类生成据我以前的试验, 也可以搞定virtual的问题, 但是有两点: 首先是不合法的东西基础不牢靠; 其次, 由于针对类和对象这一层次, 粒度还是太大。
很多时候不是咱们想怎么“纯正”的问题, 而是能不能, 和代价的问题。 总不能一味等着语言进化或者找到让自己心满意足的东西那一天吧, 瞎折腾折腾呗 :P
@xiao_p
火眼金睛..
@小生
其实我也不熟, 瞎玩...
2008-06-13 09:35 |
怪怪
#12楼
[
楼主
]
回复
引用
查看
@henry
你这个实现肯定比我这个强大, 不过肯定也重量级 :)
其实我搞这么个怪方法, 主要是为了看看在灵活性上可以走多远, 比如再设计一个规则, 一个配置方式, 可以替代继承然后override的做法, 可以变相实现多继承或Mixin,使用不同的规则, 还可能进行方法打包, 等等。
倒不是光为了AOP或者别的什么。 另外, 如果是类、接口层次的拦截, 我觉得除了Mixin接口, 也许做个预处理器, 在编译前搞些代码生成, 更加愉快。
2008-06-13 09:38 |
怪怪
#13楼
回复
引用
查看
@怪怪
针对类或接口进行拦截的粒度大?其实有时想一下我们是不是真的需要对所有东西进行aop呢?
对于我个人而言在business logic function的层面上做aop就足够了.而business logic function往往又以interface service的方式公开.
不过话也说回来每个人的设计思路都不同,所以要是MS能提供我说的那种方法就更好了,MS只是留个机会给我们在jit前对method进行基于当前appdomain的修改:)
2008-06-13 09:44 |
henry
#14楼
[
楼主
]
回复
引用
查看
@henry
呃.., 这个确实是风格不同了.. 我恨不得连现在这种形式的类都没有呢, 接口为了runtime bound的使用场景, 勉勉强强接受了...
至于公开的时候, 按对方要求配置生成一下就可以了。
2008-06-13 09:48 |
怪怪
#15楼
回复
引用
查看
string c = "fuck";
2008-06-13 10:29 |
心悦
#16楼
回复
引用
查看
个人觉得使用Lambda expressions还是会把可读性给大大的破坏了,把接口的使用变复杂了。
2008-06-13 10:56 |
阿不
#17楼
[
楼主
]
回复
引用
查看
@心悦
-_-!
@阿不
能保证接口本身所代表的契约巍不变就可以了.., 不过确实, 原来python也计划取消lambda, 说是初学者不好掌握...
2008-06-13 18:14 |
怪怪
#18楼
回复
引用
查看
看起来比C里的函数指针语法还复杂..
C# 4.0据说还要加动态语言的功能,我还等着Spec#里的DbC部分加入C#,看来,C#成为下一个C++为期不远矣 :(
2008-06-14 12:51 |
deerchao
#19楼
[
楼主
]
回复
引用
查看
@deerchao
这个, 不好下论断吧..
C++该死在那些几角旮旯和没有垃圾回收...
2008-07-18 03:58 |
怪怪
社区
新闻
新用户注册
刷新评论列表
标题
姓名
主页
Email
(只有博主才能看到)
验证码
*
看不清,换一张
[
登录
][
注册
]
内容(请不要发表任何与政治相关的内容)
Remember Me?
登录
使用高级评论
新用户注册
返回页首
恢复上次提交
[使用Ctrl+Enter键可以直接提交]
该文被作者在 2008-06-13 03:39 编辑过
相关文章:
一个绝对有效的治疗“寻常疣(干日疮,瘊子)”的方法
电脑故障处理小经验—IE无法打开链接的处理方法
利用TreeView控件动态生成无限级树
十种打领带的方法[转贴]
解决高分辨率看网页字体太小问题的一个方法
Struts常见异常信息和解决方法
相关链接:
最新IT新闻:
Google 10周年大事记
Google上下二十年
中华英才网面临外资吞并
软件收入百强张榜 华为中兴海尔列前三
马云vs孙正义:两个“疯子”的对话
博客园新闻频道
博客园首页
社区
Powered by:
博客园
Copyright © 怪怪
导航
博客园
首页
新随笔
联系
订阅
管理
<
2008年6月
>
日
一
二
三
四
五
六
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
公告
微软认为:用远见打赌是公司存在的全部。虽然许多远见最终都会以失败告终,但这并不重要,重要的是他们曾尝试过。
与我联系
发短消息
搜索
常用链接
我的随笔
我的空间
我的短信
我的评论
更多链接
我的参与
我的新闻
最新评论
我的标签
留言簿
给我留言
查看留言
我参加的小组
生活杂谈
博客园精华集出版小组
我参与的团队
北京.NET俱乐部(0/1482)
博客园精华集出版(0/43)
我的标签
敏捷
(1)
极限编程
(1)
XP
(1)
单元测试
(1)
重用
(1)
领域
(1)
方法论
(1)
DDD
(1)
随笔档案
(103)
2008年9月 (3)
2008年8月 (4)
2008年7月 (17)
2008年6月 (8)
2008年5月 (9)
2008年4月 (8)
2008年3月 (12)
2008年2月 (8)
2008年1月 (5)
2007年12月 (8)
2007年11月 (8)
2007年10月 (2)
2007年9月 (11)
最新评论
1. re: 收获: 关于辩证思维,和更多的发散
--引用--
所谓的辩证法在西方哲学上根本没有地位,就是一个失败的分支,早已
被人抛弃了。
------
请问:西方哲学成功是哪个流派或分支?
--请问“三”?
2. re: Google Chrome的新漫画不错
@路人甲居然被人注册了
^^
IT就是个杂耍的圈子,人家老巴菲特才不玩呢, 就类似我这样的小人物才会胡说八道。 不过你这个评价, 还是送给华尔街上的评论家更加合适~
--怪怪
3. re: Google Chrome的新漫画不错
妈的你说话的口气倒像巴菲特
--路人甲居然被人注册了
4. re: 收获: 关于辩证思维,和更多的发散
@三
获得信息的渠道有限, 我还不敢下你这种结论。 另外, 我考虑的不是哲学, 而是如何使用思维模式~
@1-2-3
:)
--怪怪
5. re: 收获: 关于辩证思维,和更多的发散
一看这题目就感觉挺好诧异,再一看摘要感觉很熟悉,然后看作者,呀,是怪怪,真的是怪怪……
--1-2-3
阅读排行榜
1. 如何成为一个现代程序员: 使用你的CPU, 而不是内存(9812)
2. 什么是专业? 谁更专业?(8204)
3. 业余程序员宣言: 我们就TM不专业了, 怎么了?(7673)
4. 三问TDD: 单元测试总是好的吗?(6988)
5. 技术算几斤几两又值几个钱?(5991)
评论排行榜
1. 我来当个小人吧, To 关心博客园精华集的人、包包和搅风搅雨的人(139)
2. 又论社区风气, 与程序员是干嘛地的.(124)
3. 业余程序员宣言: 我们就TM不专业了, 怎么了?(112)
4. 技术算几斤几两又值几个钱?(75)
5. 关于互联网的一些看法(70)
60天内阅读排行
1. 有关云计算和我为什么反对云计算(3732)
2. 我来当个小人吧, To 关心博客园精华集的人、包包和搅风搅雨的人(3153)
3. 两个过去的心得, 外加一个回帖整理(2363)
4. 不需要强类型, 需要强测试?(2241)
5. 回帖整理(1539)