经常看我博客的人可能会知道,我是一个喜欢搞点小技巧来实现某个功能的人。例如博客的皮肤,自己花了不少时间定义,也是为了效果丰富一些。当然,搞得最多的是从框架或类库内部取出一点小功能来用用,节省自己开发的时间。这其实也是一种复用,尤其是开发一些“扩展”的时候,例如当时尝试为UpdatePanel增加上传功能,虽然最后的结果不是很理想,但是大部分的Hack以及前后端的交互是非常成功的(最大的问题在于跨浏览器实现iframe通信)。而现在也打算总结一次这方面的简单技巧,为以后的文章贡献点引用资源。

这次我们想“复用”的内容是ASP.NET URL Routing中“解析URL”的功能。具体一点地说,就是把一个字符串根据指定的Pattern拆分成键/值对的功能。从.NET Reflector反编译System.Web.Routing.dll的结果来看,这部分的解析工作是交由RouteParser和ParsedRoute两个类完成的。这里引用一下相关的使用代码,如果您感兴趣的话,也可以阅读它们完整的实现:

public classRoute{public stringUrl{get{ ... }set{this._parsedRoute = RouteParser.Parse(value);this._url = value;}}public overrideRouteDataGetRouteData(HttpContextBasehttpContext){stringvirtualPath = ...RouteValueDictionaryvalues = this._parsedRoute.Match(virtualPath, this.Defaults);...}...
}

从代码中可以看出,RouteParser的作用是将一个Pattern(如"{controller}/{action}/{id}")转化成一个“解析器”,而这个解析器便是ParsedRoute类。在需要拆分一个URL字符串(如"Home/Index/5")的时候,便会调用ParsedRoute类的Match方法,由此得到一个RouteValueDictionary对象,其中包含了Pattern中定义的名称,和一些值的映射关系。

可能您也能够轻易实现这样的功能,不过既然微软已经帮我们做好了,我们也不妨直接使用一下,偶尔用来拆拆字符串也是挺方便的。只可惜RouteParser和ParsedRoute都是由internal修饰的,我们无法直接访问到。那么就用点小技巧吧……说实话,其实您会发现也就这么一回事,“反射”罢了。因此,我们便学着ASP.NET Routing的做法,构建两个类吧:

internal static classRouteParser{public staticParsedRouteParse(stringrouteUrl) { ... }
}internal classParsedRoute{publicRouteValueDictionaryMatch(stringvirtualPath, RouteValueDictionarydefaultValues) { ... }
}

我们目前的做法算是一种Hack,为了保证其可维护性,我会选择与目标类库/框架的接口尽可能完全一致的做法。这么做的好处在于,我可以很轻易地理解正在实现的功能,一旦出现了任何问题,就可以直接去找对应的内部实现,而不用在一堆堆的反射关系中“翱翔”。

接着便可以实现我们需要的效果了。在这里,我使用了FastReflectionLib来加快反射调用的性能。虽然我不是一个追求性能极致的Geek,但是如果有一种几乎不耗费额外代价,就能得到数百倍的性能提升,何乐而不为呢?

internal static classRouteParser{private staticMethodInvokers_parseInvoker;staticRouteParser(){varparserType = typeof(Route).Assembly.GetType("System.Web.Routing.RouteParser");varparseMethod = parserType.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public);s_parseInvoker = newMethodInvoker(parseMethod);}public staticParsedRouteParse(stringrouteUrl){ return newParsedRoute(s_parseInvoker.Invoke(null, routeUrl));}
}internal classParsedRoute{private staticMethodInvokers_matchInvoker;staticParsedRoute(){varrouteType = typeof(Route).Assembly.GetType("System.Web.Routing.ParsedRoute");varmatchMethod = routeType.GetMethod("Match", BindingFlags.Instance | BindingFlags.Public);s_matchInvoker = newMethodInvoker(matchMethod);}private objectm_instance;publicParsedRoute(objectinstance){this.m_instance = instance;}publicRouteValueDictionaryMatch(stringvirtualPath, RouteValueDictionarydefaultValues){return(RouteValueDictionary)s_matchInvoker.Invoke(this.m_instance, virtualPath, defaultValues);}
}

两个类其实都是使用反射,从类库中获取合适的MethodInfo,然后交给MethodInvoker去执行。其他的……由于代码过于简单,我都不知道还需要解释什么东西。最后就使用xUnit测试一下吧:

public classParseRouteTest{[Fact]public voidBasic_Parsing(){varparsedRoute = RouteParser.Parse("{controller}/{action}/{id}");varvalues = parsedRoute.Match("Home/Index/5", null);Assert.Equal("Home", values["controller"]);Assert.Equal("Index", values["action"]);Assert.Equal("5", values["id"]);}
}

说实话,这个方法并没有太多技术含量,由于我们将自己的实现和目标实现完全对应起来,所以我们所要做的,似乎也都是些机械的“映射”功能而已。这就引发了我的一个想法,既然很“机械”,那么为什么不去让它“自动”完成呢?例如,我们完全可以写一个类库,来实现这样的效果:

[Type("System.Web.Routing.ParsedRoute, ...")]
interfaceIParsedRoute{RouteValueDictionaryMatch(stringvirtualPath, RouteValueDictionarydefaultValues);
}[Type("System.Web.Routing.RouteParser, ...")]
interfaceIRouteParser{[Static]IParsedRouteParse(stringurl);
}

通过定义接口和标记,我们可以直接“声明”需要“挖掘”出来的类型是什么。然后自然可以有框架为我们进行匹配:

IRouteParserparser = HackFactory.Create<IRouteParser>();
IParsedRouteroute = parser.Parse("{controller}/{action}/{id}");
RouteValueDictionaryvalues = route.Match("Home/Index/5", null);

是不是一下子变得爽快了许多?简单想了想,这样的框架从技术上来说似乎并没有太多困难。

复用类库内部已有功能相关推荐

  1. JDK 9已完成功能!

    今天的马克·莱因霍尔德 ( Mark Reinhold)消息JDK 9已完成功能完善-现在该降级了 , 它宣布JDK 9的"总体功能集已冻结". 甲骨文Java平台小组的首席架构师 ...

  2. Android ListView点击之后保持更换的背景色,实现已读功能

    因为项目中有这样的需求:一般消息类或者资讯类的界面,都有类似于网易客户端的点击之后更换背景色,并且保持这个颜色,表示已读取该条信息.这个功能一开始觉得已经实现了,在我的另一篇博客上有:点击打开链接 后 ...

  3. Google Play开发者新功能:内部应用分享功能

    近期Google Play控制台中进行了部分功能的优化更新,其中导航栏的开发工具中增加了内部应用分享功能,现在我们就来为开发者介绍内部应用分享功能如何使用. 内部应用分享--无需授予访问Play控制台 ...

  4. IM热门功能讨论:为什么微信里没有消息“已读”功能?...

    本文原文由"狼和哈士奇"原创分享,本次内容有改动. 1.引言 张小龙说:微信消息不做"已读"和"未读"的功能,是因为要给人撒谎的机会,这才符 ...

  5. linux开启内部路由转发功能

    linux开启内部路由转发功能 2015-09-23 18:02:09 标签:linux开启内部路由转么功能 linux内部机器共享上网 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 ...

  6. jdk 9和jdk8_JDK 9已完成功能!

    jdk 9和jdk8 今天的Mark Reinhold消息JDK 9已完成功能完善-现在该降级了 , 它宣布JDK 9的"总体功能集已冻结". OracleJava平台小组的首席架 ...

  7. qq文件对方接收后一定会有提示吗_为什么微信、QQ不推出已读功能?因为它敢出网友就敢卸载...

    12月14日,腾讯 QQ突然发起了一个"很吓人"的调查--你希望 QQ 出已读功能吗? 在短时间内,有 超过3000 人参与,其中有 2660 人(71.6%)投票 "你 ...

  8. qq文件对方接收后一定会有提示吗_QQ要增加消息已读功能,你是否赞成?

    昨天腾讯QQ在微博发起了一项投票:你希望QQ出已读功能吗? 497人参与了投票,结果是不出意外的有近一半的人投反对票. 其实道理很简单,QQ一个交友聊天工具出这样的功能,完全没有隐私可言,例如,当你的 ...

  9. 肺功能曲线图怎么看_QQ或将推出已读功能?!你怎么看?| 微博报

    QQ回应推出已读功能 12月14日上午,腾讯QQ官方微博发起了一项投票,内容是"你希望QQ出已读功能吗?"关于这个问题QQ给网友们提供了三个选项:1.立刻马上搞快点!2.你出我就卸 ...

最新文章

  1. Strutsw2与Spring整合流程-简述
  2. ipsec 网络安全协议
  3. Vue:Elementui中的Tag与页面其它元素相互交互的两三事
  4. selenium + python自动化测试unittest框架学习(五)webdriver的二次封装
  5. xcode5 delete provisioning profile
  6. 二十二、statsmodels库的使用
  7. android ble 连续读写,Android BLE实现对蓝牙的读写
  8. 【Linux学习】GDB调试器基本命令必知必会(一)
  9. 商品管理系统c语言功能模板,C语言课程报告图书馆管理系统可做模板套用.doc
  10. “贵妇”必备的高价糖水,我给燕窝上了10年智商税
  11. 一场员工高管间的口水战,员工输了
  12. java8函数式编程闭包_java8入门必备—函数式编程思维——函数式语言向语言和运行时让渡控制权的途径——迭代让位于高阶函数、闭包...
  13. java中文输出乱码_java汉字乱码解决办法
  14. oracle11g数据库导入导出方法教程
  15. IDEA:IDEA更换主题,好看的主题汇总
  16. [代码审计]DuxCMS 2.0审计
  17. vue3 loadsh 防抖功能
  18. 禁用win10笔记本键盘
  19. android 平板桌面,RUI平板桌面
  20. 入门android开发

热门文章

  1. idea安装配置tomcat
  2. 【git私服推送文件出现的问题】refusing to update checked out branch: refs/heads/master
  3. Makefile:简单的makefile列子
  4. 计算机编码中进制的区别,计算机中的进制和编码(转载)
  5. python file tell_Python3 File tell() 方法
  6. 在python中查看关键字、需要执行,如何在一个文本文件,二进制执行搜索来搜索一个Python关键字?...
  7. mysql 安装和修改编码(utf8mb4)
  8. 前端开发-家里蹲工作环境搭建
  9. springboot启动命令linux,springboot项目命linux环境下命令启动
  10. 手动构建redis集群