C#开发人员如何使用和误用隐式和显式类型?

2021-06-30  本文已影响0人  魔人健太郎

本文译至 To var or not to var: how do C# developers use and misuse implicit and explicit typing? | SpringerLink

作者:Pierre A. Akiki
摘要:当使用“var”关键字的隐式输入法被引入C#中时,它在开发人员中引起了矛盾的意见。本文首先解释了隐式输入和显式输入之间的区别,然后概述了开发人员的意见和网上提供的指南。然后,本文报告了一项调查C#开发人员如何使用和滥用隐式和显式类型的研究结果。这项研究涉及分析10个不同开源软件项目的源代码,包括超过16,500,000行代码和超过93万个变量。本研究调查了开发者在多大程度上使用了一种影响变量类型可读性和声明长度的排版形式。它还调查了是否在一般情况下和每个软件项目中都采用了一套一致的准则。开发了一个名为“Code Analysis and Refactoring Engine for C#”(Care#)的工具,并用于进行本研究的代码分析。
关键词: C#;代码分析;隐式和显式类型;可读性;一致性

简介

过去C#变量声明只是显式的,直到C# 3.0版本引入隐式类型。隐式类型化的变量是使用“var”关键字来声明的,因此推断类型的责任被委托给了编译器。这里就出现了一个问题。什么时候开发者应该使用隐式类型来代替显式类型?

微软C#的首席架构师Anders Hejlsberg说,决定在编程语言中保留什么比决定包含什么更难(Hejlsberg 2008)。他谈到了拥有指导原则的重要性,这些原则可以让开发人员了解如何使用A language的某些争议性的功能,在C#社区内引发了一些矛盾的意见,正如在一些在线讨论中观察到的那样(Lippert,2011)。微软提供了一套关于如何使用这一特性的指导原则,但这些指导原则并没有被认为是对公约的约束(Microsoft 2015).由于C#是当今世界上最好的编程语言(TIOBE 2017),因此有必要研究一下“var”在实践中是如何使用的。

研究问题

本文研究的是C#中隐式和显式类型的使用和误用。本文试图回答的首要研究问题反映在标题中,即:C#开发人员如何使用和滥用隐式和显式类型?这个问题分为三个子问题(RQ1-RQ3),分别从源代码的可读性和一致性的角度来探究类型的使用和滥用。可读性是指读者快速、轻松理解源代码的能力(Hashim,1996)。一致性可以定义为具有统一的符号、术语和符号学(Peercy 1981)。可读性和一致性都被认为是影响可维护性的因素(Ghosh和Rana,2011)。本文的首要目标是从可读性和一致性的角度来确定C#开发人员使用隐式和显式类型的方式。问题RQ1和RQ2中的每一个问题又被划分为子问题,由本文所介绍的不同研究部分来回答。
本文还介绍了一个名为Code Analysis and Refactoring Engine for C# (Care#)的工具。这个工具可以帮助软件开发人员避免由于打字错误而对可读性和一致性可能产生的负面影响。Care#有一个分析组件,它可以检测隐式和显式变量声明,并根据它们对类型可读性和声明长度的影响将它们分类归类。Care#在决定是否需要重构之前,使用该组件对源代码进行分析。

研究动机

在《清洁代码》一书中,Robert Martin提到了许多专家的观点,认为这是一个对各种学派关于清洁代码应该是什么样子的看法(Martin 2009)。下面的句子非常简短地总结了这些观点。Jarne Stroustrup说,干净的代码应该是聪明的。Grady Booch说,干净的代码应该是简洁和直接的。Dave Thomas说,干净的代码应该是可由原作者以外的开发人员阅读。Michael Feather说,干净的代码看起来像是由关心它的人写的。Ron Jeffries说,干净的代码不包含重复的内容。如果我们在C#隐式和显式类型化的背景下思考这些意见,铭记打字的两个MS对人类读者的影响。例如,当类型不能直接读取时,用var声明一个变量,可能会影响源码的可读性. 另一方面,显式类型会造成重复,并可能导致滚动或当类型的名称很长时不得不减小字体大小。这些影响是导致开发者在使用这两种形式的输入法时意见相左的部分原因。研究专业C#项目的开发人员是以考虑可读性和一致性的方式应用排版,还是只使用各自认为合适的任何排版形式,是很有意思的。因此,本文通过分析现有的开源软件项目的源代码,研究开发人员是如何考虑排版的。

重构使引入bug的可能性最小化。它可以改善设计或实现设计的代码的可读性或性能.Care#可以重构变量声明以提高可读性,使变量的类型变得明显或使声明的长度变得更短。

需要注意的是,本文的目的并不是要严格地偏重和推广一种类型化形式(隐式或显式)而不是另一种。本文的主要目的是通过回答1.1节中提出的研究问题,了解软件开发人员如何使用隐式和显式类型化。

文章的结构

本文的其余部分组织如下。第2节解释了C#中隐式和显式类型之间的区别,以及这两种形式的类型都是强制性的情况。第3节简要介绍了微软关于在C#中使用隐式和显式类型的指南。在第4节中,我们提供了开发者对使用这两种形式的输入法的意见样本。这些意见是从在线讨论和评论中提取的。相关工作的概述将在第5节中介绍。本研究的设计和结果是为了分析软件开发者如何使用和滥用C#中的隐式和显式输入法而进行的,在第6和7节中进行了介绍和讨论。第8节介绍了本研究的有效性威胁。最后,在第9节中给出了结论和未来的工作。

在C#中使用隐式和显式类型学

C#中对隐式类型的支持始于2007年11月发布的3.0版本。在方法范围内声明的局部变量,可以通过使用声明左侧的var关键字进行隐式类型化(Microsoft 2015)。下面的示例变量声明是隐式和显式类型化的。
var car = new Car(); //隐式类型化
Car car = new Car(); //显式类型化。

微软关于在C#中使用隐式和显式输入法的指南

微软提供了一些关于何时在C#程序中使用隐式输入法的指南(Microsoft 2015)。正如这些指南的作者所说,他们的意图是提供最佳实践,以提高和促进一致性、可理解性和可维护性。遵循共同的指南,至少在同一公司内,一般来说比拥有不一致的实践更可取。这适用于各种情况,比如命名和缩进。例如,Python甚至在编译过程中强制执行缩进的一致性。一开始可能很难在共同的准则上达成一致,尤其是当所采用的表 1 对使用 im- 的限制时。

关于C#中隐式和显式输入法使用的在线讨论

在C#中,有许多关于使用隐式和显式类型的博客文章和论坛讨论。正如这些讨论所显示的那样,关于在不同情况下使用何种编码风格,开发者之间经常会有相互冲突的意见。
考虑以下在Channel 9上的例子讨论,这是一个为使用微软技术的开发者提供视频的网站(Channel9 2010)。

相关工作

据我所知,还没有针对本文所涉及的主题的广泛研究。然而,源代码分析有许多应用(Binkley 2007)。许多研究人员对源代码进行了分析,以确定可以修复的问题,从而提高软件质量。一些论文专门针对C#,而其他论文则针对不同的编程语言。本节将非常简要地概述一些与源代码分析、软件质量以及针对C#和其他编程语言的重构相关的工作。

研究设计

我们进行了一项研究,调查C#开发人员如何使用和滥用隐式和显式类型。分析了十个开源软件项目的源代码。分析包括调查类型的形式(隐式和显式)如何影响类型可读性和变量声明的长度。它还包括观察软件应用程序的两个不同版本之间的类型化形式是如何变化的。本研究有助于回答在第一节中陈述和解释的研究问题。

程序

首先,从GitHub上提供的C#项目中随机抽取10个开源软件项目样本。随机样本包括不同规模和类型的项目。我对所选软件项目的源代码事先并不了解。同时,这些项目的作者也不知道他们的代码将被用于本研究。所选的每个软件项目都包括两个版本。每个项目的两个版本被选为平均相隔1年。这样一来,这些项目很可能会有足够大的变化,从而可以观察到开发人员对类型的选择是否随着时间的推移而变化。例如,开发者可能在特定情况下将隐式重构为显式,或者反之。另一方面,这些项目不太 可能会有涉及类和方法完全重写的变化,这可能会阻止一个版本中的变量和另一个版本中的变量之间的可追溯性。

我们确定了变量声明的类别,以便根据变量声明对类型可读性的影响对其进行分类。这些类别中的一部分是根据我在C#中的经验和微软的指南初步确定的。然后,对所选的软件项目进行了初步分析,并根据确定的类别对变量声明进行了提取和分类。之后,对仍未分类的变量声明(即不符合任何一个类别)进行检查,以引出其余类别。未分类的变量通过查询数据(extract- ed variables)进行检查,这是用Care#进行分析的结果。在检查过程中发现的类别被添加到Care#中,然后重新进行分析。这个过程被重复,直到所有的类别都被确定。根据隐式类型对变量类型可读性的影响,将变量声明类别分为三组中的一组。一旦确定了所有的变量声明类别并进行了分组,就对源代码进行了重新分析。然后,手动和自动检查被形成,以识别分类中可能的错误。

研究结果

本节报告了第6节所述的研究结果,并试图回答第1节所述的研究问题;

对有效性的威胁

对结果有效性的一个威胁是从C#代码中提取变量的准确性,无论提取是纯粹基于Roslyn还是为Care#编写的自定义算法。为了减轻这种威胁,通过使用手动验证和自动单元测试来验证自动分析,以确保算法正常工作。
另一个威胁来自于数据是从10个开源C#中收集的。
可能不代表工业实践的项目。为了减轻这一威胁:
挑选过程是随机进行的,所选项目在规模(代码行数)和类型(如开发工具、商业工具)方面是多样化的。同时,分析的代码行数(超过16,500,000)与类似的代码分析研究相当,如17,600,000(Okur和Dig,2012);约4,445,415(Callaú等,2013);420,694(Ma等,2017)。

结论和今后的工作

当使用var关键字的隐式输入法被添加到C#中时,它成为一个有争议的功能。软件开发者对其使用没有达成普遍共识。本文分析了C#开发人员如何使用和滥用隐式和显式输入法。解释了这两种形式的输入法之间的区别,并介绍了开发人员在网上表达的意见样本。此外,还介绍并解释了Microsoft现有的关于使用隐式输入法的指南。

为了了解C#开发人员在实际项目中如何使用隐式和显式输入法,我们进行了一项研究。该研究检查了开发人员是否在他们的项目中始终坚持一套准则。它还检查了开发人员使用这两种类型的方式是否会影响源代码的类型可读性和冗余性,以及变量声明的长度。

本文进行的研究分析了10个开源软件项目中的每个项目的两个版本。选取的软件项目在规模和目的上都是多样化的,有超过1650万行代码和超过93万个变量。研究表明,开发人员在使用隐式和显式排版时总体上没有遵循一致的指导原则,而且这两种排版形式都存在误用的情况,可能会影响源代码的可读性。另外,当对10个分析软件项目的两个版本分别进行比较时,并没有出现明显的基于明确的准则从一种排版形式转向另一种排版形式的趋势。

本文还介绍了基于开源C#编译器Roslyn的C#代码分析和重构引擎(Care#)。Care#被用来分析本文所介绍的研究对象的项目的源代码。目前,它支持对变量声明中的输入形式进行分析和重构。在未来,Care#将被扩展到支持更多类型的分析和重构。它还将作为更多研究的起点,这些研究旨在了解和改进C#开发人员的编码习惯。一个计划中的未来扩展与基本的编码实践有关,包括硬编码值和魔数的使用。另一个计划中的未来扩展与分析用户界面(UI)表示有关,以便检测气味并建议可能的修复,这些修复可以通过重构操作自动应用。

上一篇下一篇

猜你喜欢

热点阅读