编写高质量代码的50条黄金守则-Day 01(首选隐式类型转换)

本文由比特飞原创发布,欢迎大家踊跃转载。

转载请注明本文地址:https://www.byteflying.com/archives/6455

编写高质量代码的50条黄金守则-Day 01(首选隐式类型转换),本文由比特飞原创发布,转载务必在文章开头附带链接:https://www.byteflying.com/archives/6455

该系列文章由比特飞原创发布,计划用半年时间写完全50篇文章,为大家提供编写高质量代码的一般准则。

1、概述

隐式类型转换是微软为了 C# 支持匿名类型而加入的,使用 var 通常可以使代码的可读性更强,甚至是帮我们解决一些严重的性能问题。为了清楚的明白 var 的作用机制,我们首先来看看编译器为 var 做了哪些工作?

2、编译器为var关键字做了什么?

首先 var 为语法糖,编译器在编译时根据右值推断出表达式类型,再由编译器将推断出的表达式类型写入到 IL 中,所以如下2段代码在 IL 中完全一致。

string foo = "SomeString";

var foo = "SomeString";

编译期间,编译器根据右值 “SomeString” ,可以推断出这个表达式(右值)的类型为 string 类型,于是将 var 替换为 string ,再将它写到IL中,于是以上两段初始化 foo 的代码结果完全一致。

我们再来看一下两段代码的IL:

本文示例的源代码

使用 DnSpy 解密的 IL

Microsoft 技术支持文档中 ldstr 的解释

注意:string 也是语法糖,编译时,string 被替换为 System.String 写进IL。

于是我们得到了一个重要的结论:

var 为语法糖,在编译期间就已经被编译器所决定,开发人员无法为编译器决定类型。

隐式类型转换为上述代码带来了良好的可读性,任何一名开发人员都会知道第2行代码的 var 的类型,它让我们更加的关注代码片段中我们所需要关注的部分,而不是把重点放在它的类型上。因为大多数时候,这都是没有意义的。

3、隐式类型转换所带来的良好可读性

为了明白良好可读性的问题,我们先来看一个代码片段:

var foo = new SomeType();

以上代码清晰明了,对于维护代码的人来说,它没有增加任何的理解成本,foo 的类型就是 SomeType 类型。很多优秀开源项目中的大量被使用的工厂模式,也提供了类似的方法,如下代码片段:

var huaWei = PhoneFactory.CreatePhone();

一个简单的静态工厂类 PhoneFactory ,公开了 CreatePhone 方法,阅读这段代码的开发人员,在几乎没有增加理解成本的情况下,很清楚的知道 huaWei 代表手机工厂类所生产的一个手机对象。但是下面的代码,情况可能就稍有不同了:

var result = someObject.DoSomething(someParameter);

你无法轻松的知道 result 的类型和它所表达的意义,事实上,它的不良好的可读性,表现在以下几个方面:

1、在此处,result 这个变量名并不是最好的选择;

2、someObject 的含义不明;

3、DoSomething 含糊不清;

4、无法明确的知道 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楼了。

于是,我们有了两点总结:

1、当含义明确,在代码上下文较为清楚时(简单的变量定义或工厂方法),建议优先使用 var;

2、在其它复杂情况下,尽量直接写出 var 的类型。

隐式类型转换所带来的绝非仅仅是良好的可读性,它有时可能会帮我们消除一些难以发现的性能问题,这又是怎么回事呢?

4、隐式类型转换帮我们解决严重的性能问题

人自以为自己是世界上最聪明的生物,事实上并非如此,有时候,编译器比我们聪明得多,也可靠得多。

我们看看以下两个代码片段:

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 ,并不会因此执行查询操作,真正的查询动作由var result = phones.Where(r => r.StartsWith(prefix));执行,也就是说,它的数据过滤动作由数据库引擎负责运算,最终只将符合条件的数据发送回本地,既节省了网络传递成本,又节省了运算成本,岂不是一举两得?

5、总结

1、当含义明确,在代码上下文较为清楚时(简单的变量定义或工厂方法),建议优先使用 var;

2、在其它复杂情况下,尽量直接写出 var 的类型;

3、尽可能地相信编译器,大多数时候,它比我们优秀得多。

开发人员应牢记以上开发守则,否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你、唾弃你。

该系列文章由比特飞原创发布,计划用半年时间写完全50篇文章,为大家提供编写高质量代码的一般准则。

本文由 比特飞 原创发布,欢迎大家踊跃转载。

转载请注明本文地址:https://www.byteflying.com/archives/6455

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354