编写高质量代码的30条黄金守则-Day 01(首选隐式类型转换),本文由比特飞原创发布,转载务必在文章开头附带连接:https://www.byteflying.com/archives/6455数据库
该系列文章由比特飞原创发布,计划用三个月时间写彻底30篇文章,为你们提供编写高质量代码的通常准则。网络
隐式类型转换是微软为了 C# 支持匿名类型而加入的,使用 var 一般可使代码的可读性更强,甚至是帮咱们解决一些严重的性能问题。为了清楚的明白 var 的做用机制,咱们首先来看看编译器为 var 作了哪些工做?性能
首先 var 为语法糖,编译器在编译时根据右值推断出表达式类型,再由编译器将推断出的表达式类型写入到 IL 中,因此以下2段代码在 IL 中彻底一致。spa
string foo = "SomeString"; var foo = "SomeString";
编译期间,编译器根据右值 “SomeString” ,能够推断出这个表达式(右值)的类型为 string 类型,因而将 var 替换为 string ,再将它写到IL中,因而以上两段初始化 foo 的代码结果彻底一致。.net
咱们再来看一下两段代码的IL:cdn
本文示例的源代码对象
DnSpy 的反编译结果blog
Microsoft 技术支持文档中 ldstr 的解释资源
注意:string 也是语法糖,编译时,string 被替换为 System.String 写进IL。开发
因而咱们获得了一个重要的结论:
var 为语法糖,在编译期间就已经被编译器所决定,开发人员没法为编译器决定类型。
隐式类型转换为上述代码带来了良好的可读性,任何一名开发人员都会知道第2行代码的 var 的类型,它让咱们更加的关注代码片断中咱们所须要关注的部分,而不是把重点放在它的类型上。由于大多数时候,这都是没有意义的。
为了明白良好可读性的问题,咱们先来看一个代码片断:
var foo = new SomeType();
以上代码清晰明了,对于维护代码的人来讲,它没有增长任何的理解成本,foo 的类型就是 SomeType 类型。不少优秀开源项目中的大量被使用的工厂模式,也提供了相似的方法,以下代码片断:
var huaWei = PhoneFactory.CreatePhone();
一个简单的静态工厂类 PhoneFactory ,公开了 CreatePhone 方法,阅读这段代码的开发人员,在几乎没有增长理解成本的状况下,很清楚的知道 huaWei 表明手机工厂类所生产的一个手机对象。可是下面的代码,状况可能就稍有不一样了:
var result = someObject.DoSomething(someParameter);
你没法轻松的知道 result 的类型和它所表达的意义,事实上,它的不良好的可读性,表如今如下几个方面:
一、在此处,result 这个变量名并非最好的选择;
二、someObject 的含义不明;
三、DoSomething 含糊不清;
四、没法明确的知道 someParameter 代码什么。
若是换成如下代码,状况会好不少:
var mostPopularPhone = someObject.DoSomething(someParameter);
状况有所好转,意思也更清楚。结合语义上下文,var 的类型不言自明。可是在这种状况下,我依然建议你们将代码改成如下形式:
Phone mostPopularPhone = someObject.DoSomething(someParameter);
这被我写在以前所在公司的开发手册上,我相信个人经验必定是正确的。
让咱们再来看一个新的示例:
var score = GetSomeNumber(); var rate = score / 100;
rate 的类型由变量 score 决定,而后开发者没法一眼看出 score 的类型,因此这是一个不良好的可读性的代码片断,咱们应该改成:
var score = GetSomeNumber(); double rate = score / 100;
怎么样,是否是看到这样的代码,内心舒服多了?由于你的理解成本更低了,心情舒畅了,一会儿搬砖都能搬到5楼了。
因而,咱们有了两点总结:
一、当含义明确,在代码上下文较为清楚时(简单的变量定义或工厂方法),建议优先使用 var;
二、在其它复杂状况下,尽可能直接写出 var 的类型。
隐式类型转换所带来的绝非仅仅是良好的可读性,它有时可能会帮咱们消除一些难以发现的Bug,这又是怎么回事呢?
人自觉得本身是世界上最聪明的生物,事实上并不是如此,有时候,编译器比咱们聪明得多,也可靠得多。
咱们看看如下两个代码片断:
public IEnumerable<string> GetPhoneStartsWith1(string prefix) { IEnumerable<string> phones = from r in db.Phones select r.PhoneName; var result = phones.Where(r => r.StartsWith(prefix)); return result; }
public IEnumerable<string> GetPhoneStartsWith2(string prefix) { var phones = from r in db.Phones select r.PhoneName; var result = phones.Where(r => r.StartsWith(prefix)); return result; }
以上两段代码有何不一样?GetPhoneStartsWith1 方法中的 phones 原先的返回类型应当为 IQueryable<string>,但在这里被显式声明的 phones 的 IEnumerable<string> 强制转换了,熟悉 EF 的朋友们必定知道,IQueryable<T> 为延迟加载,自己并不会马上查询数据库,事实上它只生成了一个表达式树,在最终须要使用数据的时候才会真正执行查询动做。
因而 GetPhoneStartsWith1 方法将数据库中的可能的全部数据所有取回本地,再由 var result = phones.Where(r => r.StartsWith(prefix)); 执行本地过滤,消耗了太多网络资源,而且使用了 .Net 的数据过滤机制。
GetPhoneStartsWith2 方法则否则,phones 的类型被编译器推断为 IQueryable<string> ,并不会所以执行查询操做,真正的查询动做由 var result = phones.Where(r => r.StartsWith(prefix)); 执行,也就是说,它的数据过滤动做由数据库引擎负责运算,最终只将符合条件的数据发送回本地,既节省了网络传递成本,又节省了运算成本,岂不是一箭双雕?
- 当含义明确,在代码上下文较为清楚时(简单的变量定义或工厂方法),建议优先使用 var;
- 在其它复杂状况下,尽可能直接写出 var 的类型;
- 尽量地相信编译器,大多数时候,它比咱们优秀得多。
开发人员应牢记以上开发守则,不然,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。
该系列文章由比特飞原创发布,计划用三个月时间写彻底30篇文章,为你们提供编写高质量代码的通常准则。
本文由 比特飞 原创发布,欢迎你们踊跃转载。
转载请注明本文地址:https://www.byteflying.com/archives/6455。