代码阅读性 是我提出来的概念, 独创但是没有版权。特意和代码可读性区别开来;更加强调业务概念而不是技术名词。 现给出一个极端的标准:
如果一行代码, 不能5秒钟内看出它的功能,我们可以说这段代码的阅读性不佳。
以下这段代码,是我的依赖注入框架中的一小段代码。
private readonly IDictionary<Type, resolver> item_resolvers; public IEnumerable<Interface> get_all<Interface>() { var type = typeof (Interface); foreach (var pair in item_resolvers) { if (type.IsAssignableFrom(pair.Key)) yield return (Interface) pair.Value.resolve(); } }
首先,介绍一下背景:这个方法get_all<Interface>()是从依赖注入容器中得到所有实现了指定接口<Interface>的对象实例。忽略细节,这个方法的核心是循环容器中每一个的类解析器,比较该类是否实现或继承了指定的接口。
第6行if (type.IsAssignableFrom( pair.Key ))判断实现或继承用到了C#的一个方法,IsAssignableFrom()这里是微软对该方法的定义。摘自: http://msdn.microsoft.com/ZH-cn/library/system.type.isassignablefrom.aspx
public virtual bool IsAssignableFrom(Type c)
如果 c 和当前 Type 表示同一类型,当前 Type 在 c 的继承层次结构中,当前 Type 是 c 实现的接口,c 是泛型类型参数且当前 Type 表示 c 的约束之一,或 c 表示值类型且当前 Type 表示 Nullable(Visual Basic 中的 Nullable(Of c)),则为 true。 如果不满足上述任何一个条件或者 c 为 null,则为 false。
即使看完了帮助文字,有谁知道,这个方法两边的类型,哪个是子类,哪个是父类?
对那些知道的人,我想说:恭喜你,你已经不是正常人了。我至今仍然没记住,到底哪里个是哪个。
这个方法名是一个典型的实现命名法,我猜想,它的内部的实现机制,可能就是判断一个类型是赋值过另一个类型。而作为该功能用户的我,如前面的背景所述,想知道,是谁继承了谁。因此:
首先,脱离开刚才的产品代码,我们对我们创造的新方法做一个剥离,剥离到哪去,到测试中去。
public class TypeExtensionsSpecs { class base_class { } class child_class : base_class { } private It the_class_is_not_inheried_from_itself = () => typeof(base_class).is_inherited_from(typeof(base_class)).ShouldBeFalse(); private It the_base_class_is_not_inheried_from_its_child_class = () => typeof(base_class).is_inherited_from(typeof(child_class)).ShouldBeFalse(); private It the_child_class_is_not_inheried_from_its_base_class = () => typeof(child_class).is_inherited_from(typeof(base_class)).ShouldBeTrue(); }
请先忽略那些与测试框架相关的龙套代码,如It甚至Lambda表达式, 如果有时间,后面的主题可以专门讲讲行为测试框架MSpec。这里我定义了两个类,一个子类。很明显,我的测试就是预期,子类是基类的子类,嗯有点绕口,但无论是我口头的描述,还是非常近似的测试代码描述,是很清楚明白的,是不是不到5秒能完全看懂?
public static bool is_inherited_from(this Type type, Type base_type) { return !(type == base_type) && base_type.IsAssignableFrom(type); }
即算做了n遍,到这个实现代码我几乎仍然是拼凑以期让测试通过,因为我实在是弄出清楚IsAssignableFrom的方向性。只有测试让我更清楚些。
技术上,没有别的,主要用到了.Net的新特性 Extension
说新其实也不新了。至少我都用了3、5年了。我想这个名称应该来源于所谓的开闭原则,对修改关闭,对扩展开放,这就是一个扩展功能,还是名副其实。
作为完结我们看看应用新方法之后的原代码。是不是好懂很多,也就减少了bug的机会,你想写反都难!
private readonly IDictionary<Type, resolver> item_resolvers; public IEnumerable<Interface> get_all<Interface>() { var type = typeof (Interface); foreach (var pair in item_resolvers) { /* 新代码 */ if (pair.Key.is_inherited_from(type)) yield return (Interface) pair.Value.resolve(); } }
刚好,说到这里,在阅读性上,我们这一段代码还可走的更远,如用Linq来替换循环和过滤的功能,等等。不管,我们现在有多不完美,但是至少我们是朝着正确的方向!
(本文版权属于© 2012 - 2013 予沁安 | 转载请注明作者和 出处)