Visual Basic 的新增功能

本文列出了每个版本的 Visual Basic 的关键功能名称,其中详细说明了最新版本的语言中的新增功能和增强功能。

当前版本

Visual Basic 16.9 / Visual Studio 2019 版本 16.9
有关新功能,请参阅 Visual Basic 16.9

可以从 .NET 下载页下载最新的 .NET SDK。

旧版

Visual Basic 16.0 / Visual Studio 2019 版本 16.0
有关新功能,请参阅 Visual Basic 16.0

Visual Basic 15.5 / Visual Studio 2017 版本 15.5
有关新功能,请参阅 Visual Basic 15.5

Visual Basic 15.3 / Visual Studio 2017 版本 15.3
有关新功能,请参阅 Visual Basic 15.3

Visual Basic 15 / Visual Studio 2017
有关新功能,请参阅 Visual Basic 2017

Visual Basic /Visual Studio 2015
有关新功能,请参阅 Visual Basic 14

Visual Basic /Visual Studio 2013
.NET 编译器平台的技术预览(“Roslyn”)

Visual Basic /Visual Studio 2012
Asyncawait 关键字、迭代器、调用方信息属性

Visual Basic、Visual Studio 2010
自动实现的属性、集合初始值设定项、隐式行延续、动态、泛型共同/逆差、全局命名空间访问

Visual Basic /Visual Studio 2008
语言集成查询(LINQ)、XML 文本、本地类型推理、对象初始值设定项、匿名类型、扩展方法、本地 var 类型推理、lambda 表达式、 if 运算符、分部方法、可为 null 的值类型

Visual Basic /Visual Studio 2005
My类型和帮助程序类型(访问应用、计算机、文件系统、网络)

Visual Basic/Visual Studio .NET 2003
位移运算符,循环变量声明

Visual Basic/Visual Studio .NET 2002
Visual Basic .NET 的第一个版本

Visual Basic 16.9

Visual Basic 16.9 允许使用仅初始化属性。

Visual Basic 16.0

Visual Basic 16.0 侧重于向 .NET Core 提供 Visual Basic 运行时(microsoft.visualbasic.dll)的更多功能,是 Visual Basic 的第一个版本,侧重于 .NET Core。 .NET Core 3.0 中添加了依赖于 WinForms 的 Visual Basic 运行时部分。

语句中的更多位置允许的注释

在 Visual Basic 15.5 及更早版本中,仅允许在空行、语句末尾或允许隐式行延续的语句中的特定位置使用注释。 从 Visual Basic 16.0 开始,在显式行延续之后以及以空格后跟下划线的行上的语句中,也允许注释。

Public Sub Main()
    cmd.CommandText = ' Comment is allowed here without _
        "SELECT * FROM Titles JOIN Publishers " _ ' This is a comment
        & "ON Publishers.PubId = Titles.PubID " _
 _ ' This is a comment on a line without code
        & "WHERE Publishers.State = 'CA'"
End Sub

优化的浮点到整数转换

在早期版本的 Visual Basic 中, 将 DoubleSingle 值转换为整数的性能相对较差。 将以下任一方法返回的值传递给内部 Visual Basic 整数转换函数之一(CByte、CShort、CInt、CLng、CSByte、CUShort、CUShort、CUInt、CULng)、CUInt、CULng 或以下任一方法返回的值将隐式转换为整型时Off,Visual Basic 16.0 会显著提高浮点转换到整数的性能:

此优化允许代码更快地运行 -- 对于执行大量转换为整数类型的代码,其速度高达两倍。 以下示例演示了受此优化影响的一些简单方法调用:

Dim s As Single = 173.7619
Dim d As Double = s

Dim i1 As Integer = CInt(Fix(s))               ' Result: 173
Dim b1 As Byte = CByte(Int(d))                 ' Result: 173
Dim s1 AS Short = CShort(Math.Truncate(s))     ' Result: 173
Dim i2 As Integer = CInt(Math.Ceiling(d))      ' Result: 174
Dim i3 As Integer = CInt(Math.Round(s))        ' Result: 174

请注意,此截断而不是舍入浮点值。

Visual Basic 15.5

非尾随命名参数

在 Visual Basic 15.3 和更早版本中,当方法调用包括按位置和按名称排列的参数时,位置参数必须位于命名参数之前。 从 Visual Basic 15.5 开始,只要到最后一个位置参数的所有参数都处于正确的位置,位置参数和命名参数就可以按任意顺序显示。 当命名参数用于使代码更具可读性时,这尤其有用。

例如,以下方法调用在命名参数之间具有两个位置参数。 命名参数明确表示值 19 表示年龄。

StudentInfo.Display("Mary", age:=19, #9/21/1998#)

Private Protected 成员访问修饰符

此新关键字组合定义一个成员,该成员可由其包含类中的所有成员以及派生自包含类的类型访问,但前提是它们也位于包含程序集中。 由于无法继承结构, Private Protected 因此只能应用于类的成员。

前导十六进制/二进制/八进制分隔符

Visual Basic 2017 添加了对下划线字符(_)作为数字分隔符的支持。 从 Visual Basic 15.5 开始,可以使用下划线字符作为前缀和十六进制、二进制或八进制数字之间的前导分隔符。 以下示例使用前导数字分隔符将 3,271,948,384 定义为十六进制数:

Dim number As Integer = &H_C305_F860

若要将下划线字符用作前导分隔符,必须将以下元素添加到 Visual Basic 项目(*.vbproj)文件中:

<PropertyGroup>
  <LangVersion>15.5</LangVersion>
</PropertyGroup>

Visual Basic 15.3

命名元组推理

从变量中分配元组元素的值时,Visual Basic 会从相应的变量名称推断元组元素的名称;无需显式命名元组元素。 以下示例使用推理创建包含三个命名元素的元组,statestateName以及capital

Const state As String = "MI"
Const stateName As String = "Michigan"
Const capital As String = "Lansing"
Dim stateInfo = (state, stateName, capital)
Console.WriteLine($"{stateInfo.stateName}: 2-letter code: {stateInfo.State}, Capital {stateInfo.capital}")
' The example displays the following output:
'      Michigan: 2-letter code: MI, Capital Lansing

其他编译器开关

Visual Basic 命令行编译器现在支持 -refout-refonly 编译器选项来控制引用程序集的输出。 -refout 定义引用程序集的输出目录, -refonly 指定仅通过编译输出引用程序集。

Visual Basic 15

元组

元组是一种轻型数据结构,最常用于从单个方法调用返回多个值。 通常,若要从方法返回多个值,必须执行下列作之一:

  • 定义自定义类型(或 Class )。Structure 这是一个重量级的解决方案。

  • 除了从方法返回值外,还定义一个或多个 ByRef 参数。

Visual Basic 对元组的支持使你能够快速定义元组,选择性地为其值分配语义名称,并快速检索其值。 以下示例包装对 TryParse 方法的调用并返回元组。

Imports System.Globalization

Public Module NumericLibrary
    Public Function ParseInteger(value As String) As (Success As Boolean, Number As Integer)
        Dim number As Integer
        Return (Integer.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, number), number)
    End Function
End Module

然后,可以使用如下所示的代码调用该方法并处理返回的元组。

Dim numericString As String = "123,456"
Dim result = ParseInteger(numericString)
Console.WriteLine($"{If(result.Success, $"Success: {result.Number:N0}", "Failure")}")
Console.ReadLine()
'      Output: Success: 123,456

二进制文本和数字分隔符

可以使用前缀 &B&b. 此外,可以使用下划线字符 _作为数字分隔符来提高可读性。 以下示例使用这两个功能来分配值 Byte 并将其显示为十进制数、十六进制数和二进制数。

Dim value As Byte = &B0110_1110
Console.WriteLine($"{NameOf(value)}  = {value} (hex: 0x{value:X2}) " +
                  $"(binary: {Convert.ToString(value, 2)})")
' The example displays the following output:
'      value  = 110 (hex: 0x6E) (binary: 1101110)      

有关详细信息,请参阅 字节整数SByteUIntegerULongUShort 数据类型的“文本赋值”部分。

支持 C# 引用返回值

C# 支持引用返回值。 也就是说,当调用方法收到引用返回的值时,它可以更改引用的值。 Visual Basic 不允许使用引用返回值创作方法,但它允许使用和修改引用返回值。

例如,用 C# 编写的以下 Sentence 类包括一个 FindNext 方法,该方法查找以指定子字符串开头的句子中的下一个单词。 字符串作为引用返回值返回,通过 Boolean 对方法的引用传递的变量指示搜索是否成功。 这意味着,除了读取返回的值外,调用方还可以对其进行修改,并且修改反映在类中 Sentence

using System;

public class Sentence
{
    private string[] words;
    private int currentSearchPointer;

    public Sentence(string sentence)
    {
        words = sentence.Split(' ');
        currentSearchPointer = -1;
    }

    public ref string FindNext(string startWithString, ref bool found)
    {
        for (int count = currentSearchPointer + 1; count < words.Length; count++)
        {
            if (words[count].StartsWith(startWithString))
            {
                currentSearchPointer = count;
                found = true;
                return ref words[currentSearchPointer];
            }
        }
        currentSearchPointer = -1;
        found = false;
        return ref words[0];
    }

    public string GetSentence()
    {
        string stringToReturn = null;
        foreach (var word in words)
            stringToReturn += $"{word} ";

        return stringToReturn.Trim();
    }
}

最简单的形式是,可以使用如下代码修改句子中找到的单词。 请注意,不向方法分配值,而是将值分配给方法返回的表达式,即引用返回值。

Dim sentence As New Sentence("A time to see the world is now.")
Dim found = False
sentence.FindNext("A", found) = "A good" 
Console.WriteLine(sentence.GetSentence()) 
' The example displays the following output:
'      A good time to see the world is now.

不过,此代码存在一个问题,即如果未找到匹配项,该方法将返回第一个单词。 由于该示例不检查参数的值 Boolean 以确定是否找到匹配项,因此如果没有匹配项,它将修改第一个单词。 以下示例通过将第一个单词替换为自身(如果没有匹配项)来更正此错误。

Dim sentence As New Sentence("A time to see the world is now.")
Dim found = False
sentence.FindNext("A", found) = IIf(found, "A good", sentence.FindNext("B", found)) 
Console.WriteLine(sentence.GetSentence()) 
' The example displays the following output:
'      A good time to see the world is now.

更好的解决方案是使用引用返回值传递给的帮助程序方法。 然后,帮助程序方法可以修改通过引用传递给它的自变量。 下面的示例执行该作。

Module Example
   Public Sub Main()
      Dim sentence As New Sentence("A time to see the world is now.")
      Dim found = False
      Dim returns = RefHelper(sentence.FindNext("A", found), "A good", found) 
      Console.WriteLine(sentence.GetSentence()) 
   End Sub
   
   Private Function RefHelper(ByRef stringFound As String, replacement As String, success As Boolean) _ 
                    As (originalString As String, found As Boolean) 
      Dim originalString = stringFound
      If found Then stringFound = replacement
      Return (originalString, found)   
   End Function
End Module
' The example displays the following output:
'      A good time to see the world is now.

有关详细信息,请参阅 引用返回值

Visual Basic 14

NameOf

可以获取类型或成员的非限定字符串名称,以便在错误消息中使用,而无需对字符串进行硬编码。 这样,代码就可以在重构时保持正确。 此功能还可用于连接模型视图控制器 MVC 链接并触发属性更改事件。

字符串内插

可以使用字符串内插表达式来构造字符串。 内插字符串表达式类似于包含表达式的模板字符串。 与 复合格式相比,内插字符串更易于理解参数。

Null 条件成员访问和索引

在执行成员访问()或索引(?.?[])作之前,可以采用非常轻的语法测试 null。 这些运算符可帮助你编写更少的代码来处理 null 检查,尤其是用于进入数据结构。 如果左侧作数或对象引用为 null,则作返回 null。

多行字符串文本

字符串文本可以包含换行序列。 不再需要使用旧工作 <xml><![CDATA[...text with newlines...]]></xml>.Value

注释

可以在隐式行延续、初始值设定项表达式和 LINQ 表达式术语之间放置注释。

更智能的完全限定名称解析

给定的代码(例如 Threading.Thread.Sleep(1000),Visual Basic 用于查找命名空间“Threading”),发现它与 System.Threading 和 System.Windows.Threading 之间不明确,然后报告错误。 Visual Basic 现在同时考虑这两个可能的命名空间。 如果显示完成列表,Visual Studio 编辑器会列出完成列表中的这两种类型的成员。

第一年日期文本

可以使用 yyyy-mm-dd 格式 #2015-03-17 16:10 PM#的日期文本。

只读接口属性

可以使用 readwrite 属性实现只读接口属性。 该接口保证最低功能,它不会阻止实现类允许设置属性。

TypeOf <expr> IsNot <类型>

为了提高代码的可读性,现在TypeOfIsNot可以使用 。

#Disable 警告 <ID> 和 #Enable 警告 <ID>

可以为源文件中的区域禁用和启用特定警告。

XML 文档注释改进

编写文档注释时,你将获得智能编辑器并生成对验证参数名称、正确处理 crefs (泛型、运算符等)的支持、着色和重构。

部分模块和接口定义

除了类和结构,还可以声明部分模块和接口。

方法主体中的 #Region 指令

可以将 #Region...#End 区域分隔符放在文件、函数内部,甚至可以跨函数主体。

替代定义是隐式重载

如果将修饰符添加到 Overrides 定义,编译器会隐式添加 Overloads ,以便在常见情况下键入更少的代码。

特性参数中允许的 CObj

编译器用于提供 CObj(...)在属性构造中使用时不是常量的错误。

从不同的接口声明和使用不明确的方法

以前,以下代码生成了阻止你声明 IMock 或调用 GetDetails 的错误(如果这些错误已在 C# 中声明):

Interface ICustomer
  Sub GetDetails(x As Integer)
End Interface

Interface ITime
  Sub GetDetails(x As String)
End Interface

Interface IMock : Inherits ICustomer, ITime
  Overloads Sub GetDetails(x As Char)
End Interface

Interface IMock2 : Inherits ICustomer, ITime
End Interface

现在,编译器将使用普通重载解析规则来选择最适合 GetDetails 调用的规则,并且可以在 Visual Basic 中声明接口关系,如示例中所示的接口关系。

另请参阅