写点什么

Visual Basic 14 的语言特性

  • 2015-02-04
  • 本文字数:4633 字

    阅读完需:约 15 分钟

与 Visual Studio 类似,Visual Basic 也将从版本 12 直接跳到 14。虽然新版本中的许多特性对于 C#来说也是首次引进,但仍然有大量的功能增强是特别针对 VB 的,旨在简化 VB 的使用。本文列举了一些最令我们感兴趣的特性。

对 Null 的支持

新版本的一个特性是对 null 值的支持,该特性使用?. 操作符。这一特性与 C#相同,如果操作符左方的表达式返回值不为 null,则继续计算右方表达式。在处理外部资源所返回的少量数据时,该特性尤其有用。举例来说:

If customer.PrimaryResidence IsNot Nothing AndAlso customer.PrimaryResidence.Garage IsNot Nothing AndAlso property.PrimaryResidence.Garage.Cars = 2 Then Print(“Two Car Garage”)

这段代码将被简化成以下语句:

复制代码
If property.PrimaryResidence?.Garage?.Cars = 2 Then Print("Two Car Garage")

除此之外,还可以将该操作符与 If 操作符进行结合,实现为表达式提供某个默认值的功能:

复制代码
Dim numberOfCarPorts = If(property.PrimaryResidence?.Garage?.Cars, 0)

C#与 VB 并不是唯一两种支持这种 null 处理方式的语言。在 Apple 的产品中得到广泛应用的 Objective-C 语言默认就支持该行为。尤其是它的方法调用也使用. 操作符,其工作方式就类似于 VB 中的?. 操作符。

在 Objective-C 的社区中,人们对该特性的评价褒贬不一。某些开发者非常喜爱这项功能,因为他们在进行方法调用时无需担心空引用异常的产生。而另一些开发者则对此感到痛恨,因为在问题发生时,他们不会看到空引用异常的产生,只会看到方法调用失败。如此一来他们就会感到困惑,为什么方法返回了 null,而不是返回有效值或抛出异常。

元编程

在 Visual Basic 12 中,我们首次看到了 CallerNameAttribute 这一特性的引入。虽然这一特性解决了属性变更通知(property change notification)的问题,但它的通用性还不足以解决另外一部分问题,在这些问题中需要一个以字符串形式表达的唯一标识符,在这种情况下,需要使用到 NameOf 这个操作符。

以下这个示例是由来自 Visual Basic 团队的 Lucian Wischik 所提供的,其中包括对参数进行验证的逻辑。

复制代码
Function Lookup(name As String) As Customer
If name is Nothing Then Throw New ArgumentNullException(NameOf(name))

这种方式能够避免在修改了参数名称的时候,忘记修改了所抛出异常的构造函数中所定义的字符串。由于 NameOf 操作符实际上创建了一个常量,因此你可以在任何需要使用硬编码字符串的时候使用该操作符。

字符串插值(Interpolation)

自从十年以前.NET 初次问世的时候,String.Format 这个方法就要求开发者们对参数的数量进行计数。多年以来,由于计数错误所产生的 bug 可谓是不计其数。字符串插值这一技术最初是由 Mono 团队为 C#语言所创建的,它彻底解决了计数这种糟糕的做法。

插值字符串是由 $”开头的,而不是单单使用”。对于每个你需要插入值的位置,都要使用一对大括号进行转义,这一点与 String.Format 的做法是相同的。另一个与 String.Format 相同的地方在于可以在转义中加入格式化选项。在下面这个简单的示例中出现了两个变量,name 和 total,后者将被格式化为货币格式。

复制代码
Dim message = $"Hello {name}, your amount due is {total:C2}"

该语法本身就使用了 String.Format 方法,因此使用者同样需要注意在适当的场合进行转义,考虑一下以下字符串:

复制代码
Dim requestUrl = $"http://{server}/customer?name={customerName}"

这段代码会产生一个 bug,开发者实际上需要的是以下代码:

复制代码
Dim requestUrl = $"http://{server}/customer?name={UrlEncode(customerName)}"

FormattedString 对象

乍一看插值字符串的语法,似乎无法处理从外部资源中获取字符串的场景,例如从本地化表或资源字典中获取字符串。不过,微软正在努力实现这一功能。Lucian Wischik 写道:

不仅能够使用在不同的语言文化中,而且还能够从中抽取出原始的格式化字符串或者是参数(举例来说,如果你打算在 SQL 查询中使用该语法,或者会需要对参数进行转义,以避免产生字符串注入攻击)。但目前为止,我们还没有完全决定该语法的设计规格。

按照当前的规格声明草稿所说,插值字符串可以是一个常规的字符串,也可以由一个名为 FormattedString 的对象实现。当你试图将某个插值字符串赋值给一个实现了 IFormattable 接口的变量或是参数时,系统会自动创建一个 FormattedString 类型的实例。

该对象的 IFormattable.ToString 方法接受一个类型为 IFormatProvider 类型的参数,使用该参数能够重写格式化相关的行为。

复制代码
string IFormattable.ToString(string ignored, IFormatProvider formatProvider)
{
return String.Format(formatProvider, format, args);
}

在上面一段代码中,format 与 args 两个参数分别代表了待插值的原始字符串,以及它所对应的值。

多行字符串

在 VB 中新加入的一个特性是多行字符串。实现它不需要任何特殊的语法,只需要在希望分行的地方省略引号即可。根据源代码文件所使用的换行符的不同,该换行符会自动在 vbCrlf、vbCr 及 vbLf 等符号间进行选择。对于 Visual Studio 的用户来说,基本上都会选择 vbCrlf。

在目前,某些开发者会选择在 XML 文本中使用 CData 段落来模仿这一特性,这种方式虽然能够实现所需要的效果,但显得有些冗长与笨拙。

属性

自动属性现在可以标记为只读了。可以在声明时为该属性赋值,也可在构造函数中进行赋值。

该语法的使用方式应该不会出乎你的意料:

复制代码
Public ReadOnly FirstName As String = "Anonymous"
Public ReadOnly LastName As String
Public Sub New (firstName As String, lastName As String)
Me.FirstName = firstName
Me.LastName = lastName
End Sub

在使用这一特性时,应当考虑到某些特殊情况。要理解这些情况,你首先必须理解参数传递的 copy-in 和 copy-out 概念。CLR 只允许你为变量及字段进行引用传递(即 C#中的 ref 或 out 操作符)。但在 VB 中,你也能够为属性进行引用传递。

为了缓解这两者之间的分歧,VB 会在准备进行函数调用时创建一个本地变量,该属性的值会被拷贝到这个本地变量中。该本地变量随后被传递至函数中,函数体能够修改该本地变量的值。当该函数返回时,本地变量的值会拷贝回属性中。

在使用只读的自动属性时,将会应用以下规则:

  1. 如果你在构造函数中的某个 lambda 表达式中使用只读自动属性,编译器会提示语法错误。
  2. 如果在构造函数或初始化器中使用只读自动属性,将应用 copy-in 与 copy-out 规则。Copy-out 操作会将值写入系统为属性生成的字段中。
  3. 如果不在构造函数或初始化器中使用只读自动属性,则只会应用 copy-in 规则。Copy-out 操作根本不会发生,但也不会产生任何语法错误。

这些规则都是基于只读字段的工作原理所产生的。

注释

现在,在一个多行语句的每一行末尾都可以加入注释了。在之前的版本中,只能在多行语句的最后一行末尾加入注释。请看以下示例:

复制代码
Dim emailList =
From c in Customers
Where c.IsActive 'ignore inactive customers
And Not c.DoNotEmail 'we don’t need another spam violation
Select c.FullName, c.EmailAddress

结构体

结构体现在能够支持无参构造函数了。虽然 CLR 本身就支持这一特性,但还没有主流的编程语言实现了这一特性,其原因是构造函数的运行时机并不明确。举例来说,在创建某个结构体的数组时,该结构体的构造函数并不会运行。

如果你的代码是 myStruct = new MyStructure(),那很显然该构造函数会立即执行。而如果你的代码是 myStruct = Nothing,则显然不会执行构造函数。但在某个本地变量或成员变量自动初始化时又是否会执行构造函数呢?无论你选择哪一种答案,总会让一部分人感觉不爽。

数据文本(Data Literals)

从今年开始,数据文本(对于 JSON 格式来说非常重要的一个特性)终于改为使用符合 ISO 标准的格式了。在过去,数据文本一直使用基于美国的格式化形式,对于居住在欧洲的人来说就会产生一些迷惑。

  • 老风格:#3/4/2005#(是三月四日,还是四月三日?)
  • 新风格:#2005-4-3#

与 C#的互操作性

Overrides 修饰符将会隐含使用 Overloads 修饰符。在过去,VB 的开发者必须同时使用这两种修饰符,才能保证 C#的使用者在使用由 VB 所创建的类库时能够调用正确的重载方法。

接口模糊性

在 C#中使用接口继承这一特性时,会造成不易判断到底是哪个接口方法被调用的问题。在 VB 中不允许出现这种场景,但由于 C#允许这一特性,会造成出现某些 VB 无法实现的接口的情况。(在 Microsoft Dynamics 的某个产品中就数次出现这种情况。)

相对于 C#中所使用的“通过名称隐藏”(hide-by-name)的重载规则,VB 14 中将对这一限制进行放宽,转而使用一种(对 VB 来说)更传统的方式,即“通过签名隐藏”的规则。

命名空间解析

VB 也曾在命名空间解析这一问题上栽过跟斗,考虑一下以下代码:

Threading.Thread.Sleep(1000)

按 Lucian Wischik 所说:

之前,VB 会尝试查找“Threading”这一命名空间,由于它无法分辨 System.Threading 和 System.Windows.Threading 的区别,因此直接报错。现在,VB14 会同时支持这两种可能匹配的命名空间。如果你在代码编辑器输入 Threading.,那么在输入. 号之后,你会在智能提示中看到对这两个命名空间的支持。

类似的情况还有许多,举例来说:在编写 Winforms 应用时,ComponentModel.INotifyPropertyChanged 事件就会无法分辨 System.ComponentModel 及 System.Windows.Forms.ComponentModel,这一问题如今将不复存在。

TypeOf 和 IsNot

微软在十年前就创建了 IsNot 操作符,自那以来,就不断有 VB 的开发者要求微软允许在 TypeOf 表达式中使用 IsNot 操作符,举例如下:

复制代码
If TypeOf sender IsNot Button Then

预处理指令

VB 14 为预处理指令提供了两点改进之处。

Regi7on

Region 将能够在函数体中进行使用,甚至是跨两个函数体进行使用。

关闭警告

与 C#相同,Visual Basic 现在也能够关闭对某一个代码块的编译警告了。在规格说明中提供了一个示例:

复制代码
#Disable Warning BC42356 'suppress warning about no awaits in this method

通常来说,开发者会通过某个指令在该代码文件的其它地方重新打开这一警告

复制代码
#Enable Warning BC42356

如果该警告的 ID 中包含了空格或标点符号,则必须使用引号。微软的工具不会自动为你完成这一点,不过由 Roslyn 所编写的第三方分析器规则或许能实现这一点。

VB 的快速修复(Quick Fix)特性能够通过自动添加这些指令实现绕过某些警告的目的。这一点对于之前提到的第三方分析器规则来说尤其有用,因为你不一定能够很快地找到对应的 ID。

XML 文档验证

目前来说,VB 编译器会忽略 XML 文档的内容。而在 VB 14 中,编译器就会试图在文档中查找错误,例如不正确的参数引用名称。它还能够“正确地处理 crefs 标签中的泛型与操作符”。

部分模块(partial module)与接口声明

与类和结构体类型,你现在能够将模块与接口声明为部分(partial)了。通常来说,这一特性是为代码生成器所准备的,但也能够在跨多个平台分享代码时发挥作用。

关于作者

Jonathan Allen的第一份工作是在二十世纪 90 年代后期时,参与某个医疗诊所的管理信息系统项目的开发,将该项目由 Access 及 Excel 逐渐转化为企业级解决方案。随后,当他为某个商业部门的自动交易系统工作了五年之后,他决定转为进行高端用户界面的开发。在空余时间,他喜欢阅读及撰写一些关于西方武术在 15 世纪至 17 世纪之间发展的文章。

查看英文原文: Article: Visual Basic 14 Language Features

2015-02-04 23:113976
用户头像

发布了 428 篇内容, 共 176.7 次阅读, 收获喜欢 38 次。

关注

评论

发布
暂无评论
发现更多内容

Java代理模式,一次复习完4种动态代理实现方式

爱好编程进阶

Java 程序员 后端开发

开发改了接口,经常忘通知测试,有什么好的解决方案吗?

Liam

测试 Postman 自动化测试 测试工具 测试自动化

阿里云人工智能创新发布-工业五金图片搜索

视觉智能

拍照购物 以图搜图 图像搜索 拍立淘

Java基础06 数组基础

爱好编程进阶

Java 程序员 后端开发

必示科技入围未来银行科技服务商Top100榜单

BizSeer必示科技

it资产管理系统解决方案

低代码小观

资产管理 企业管理系统 CRM系统 IT治理 资产安全

netty系列之:使用Jboss Marshalling来序列化java对象

程序那些事

Java Netty 程序那些事 4月月更

企业如何应对知识管理中的文档管理

小炮

知识管理

在亚马逊云科技上搭建静态无服务器 Wordpress,每天仅需 0.01 美元

亚马逊云科技 (Amazon Web Services)

Serverless CDN WordPress

如何成为一名亚马逊云科技 Community Builder

亚马逊云科技 (Amazon Web Services)

Cloud 亚马逊云科技 career

离AI无处不在还有多远?从一个英特尔开源平台开始实现

科技新消息

有更新!鸿蒙智联生态产品《接入智慧生活App开发指导》(官方版)

HarmonyOS开发者

HarmonyOS 鸿蒙智联

RNG战队LPL春季赛夺冠!中国电竞产业未来如何实现“破与立”?

易观分析

电竞产业

堡垒机是什么意思?别称是啥?

行云管家

网络安全 防火墙 数据安全 堡垒机

DRBD是什么意思?优缺点是什么?

行云管家

高可用 运维 HA高可用

带你认识2种基于深度学习的场景文字检索算法

华为云开发者联盟

深度学习 计算机视觉 文本检测 场景文本检索 文字检索

智能手表的下半场,机遇与挑战并存

Speedoooo

物联网 小程序容器 智能手表 智能穿戴

智慧运维平台之全息监控

鲸品堂

运维 通信 运营商

免费IT自动化运维平台- ETL调度批量管理工具 TASKCTL 8.0 作业设计功能使用

敏捷调度TASKCTL

数据仓库 数据治理 运维自动化 ETL任务 TASKCTL

9个国内/外行业 NPS (净推荐值)基准网站

龙国富

NPS

Cube 技术解读 | Cube 渲染设计的前世今生

蚂蚁集团移动开发平台 mPaaS

mPaaS Android; cube

一个平面设计师的异想世界

万事ONES

研发管理 设计师 ONES workbalance

OpenHarmony技术日成功举办,全球下载次数高达6300万

科技汇

基于Sharding-JDBC的订单分库⽅案

领创集团Advance Intelligence Group

直播预告|青藤云安全 x 极狐,云原生 DevSecOps 安全左移全解析

极狐GitLab

云原生 DevSecOps 主机安全 容器安全 软件安全

3.0.0 alpha 重磅发布!九大新功能、全新 UI 解锁调度系统新能力

Apache DolphinScheduler

Bigdata DolphinScheduler workflow Open Source apache 社区

macOS 安装 Nebula Graph 看这篇就够了

NebulaGraph

macos 图数据库 安装部署

列举GaussDB(DWS)常见的查询时索引失效场景

华为云开发者联盟

索引 GaussDB(DWS) 隐式类型转化 GIN索引 analyze

OpenHarmony技术日圆满举行 | 3.1 Release版本重磅发布,生态落地初具规模

OpenHarmony开发者

OpenHarmony 技术日

华为推出OpenHarmony生态使能服务 加速OpenHarmony商用发行版落地

科技汇

Docker 镜像知多少?

Daocloud 道客

云原生 Docker 镜像

Visual Basic 14的语言特性_语言 & 开发_Jonathan Allen_InfoQ精选文章