对象初始值设定项:命名类型和匿名类型 (Visual Basic)

利用对象初始值设定项,你可以使用单个表达式指定复杂对象的属性。 它们可用于创建命名类型和匿名类型的实例。

声明

命名类型和匿名类型的实例声明看起来几乎完全相同,但作用并不相同。 每个类别都有自己的功能和限制。 以下示例显示了一种方便方法,通过使用对象初始值设定项列表来声明和初始化命名类 Customer 的实例。 请注意,类的名称是在关键字 New 之后指定的。

Dim namedCust = New Customer With {.Name = "Terry Adams"}

匿名类型没有可用的名称。 因此,匿名类型的实例化不能包含类名。

Dim anonymousCust = New With {.Name = "Hugo Garcia"}

这两个声明的要求和结果并不相同。 对于 namedCust,具有 Name 属性的 Customer 类必须已经存在,并且声明还创建了该类的实例。 对于 anonymousCust,编译器定义一个具有一个属性(即名为 Name 的字符串)的新类,并创建该类的一个新实例。

命名类型

对象初始值设定项提供了一种简单的方法来调用某种类型的构造函数,然后在单个语句中设置一些或所有属性的值。 编译器为语句调用适当的构造函数:如果没有提供参数,则调用无参数构造函数;如果发送了一个或多个参数,则调用参数化构造函数。 之后,指定的属性将按初始值设定项列表中显示的顺序进行初始化。

初始值设定项列表中的每个初始化都包含将初始值分配给类的成员。 成员的名称和数据类型在定义类时确定。 在以下示例中,Customer 类必须存在,并且必须具有可接受字符串值的名为 NameCity 的成员。

Dim cust0 As Customer = New Customer With {.Name = "Toni Poe", 
                                           .City = "Louisville"}

你也可以使用以下代码获得相同的结果:

Dim cust1 As New Customer With {.Name = "Toni Poe", 
                                .City = "Louisville"}

这些声明中的每一个都相当于下面的示例,该示例使用无参数构造函数创建 Customer 对象,然后使用 With 语句指定 NameCity 属性的初始值。

Dim cust2 As New Customer()
With cust2
    .Name = "Toni Poe"
    .City = "Louisville"
End With

例如,如果 Customer 类包含允许为 Name 发送值的参数化构造函数,也可通过以下方式声明和初始化 Customer 对象:

Dim cust3 As Customer = 
    New Customer("Toni Poe") With {.City = "Louisville"}
' --or--
Dim cust4 As New Customer("Toni Poe") With {.City = "Louisville"}

不必初始化所有属性,如以下代码所示。

Dim cust5 As Customer = New Customer With {.Name = "Toni Poe"}

但初始化列表不能为空。 未初始化的属性保留其默认值。

使用命名类型进行类型推理

可以通过结合对象初始值设定项和本地类型推断来缩短 cust1 的声明代码。 这样,你就可以在变量声明中省略 As 子句。 变量的数据类型是根据由赋值创建的对象类型推断出来的。 在以下示例中,cust6 的类型为 Customer

Dim cust6 = New Customer With {.Name = "Toni Poe", 
                               .City = "Louisville"}

关于命名类型的注解

  • 类成员不能在对象初始值设定项列表中进行多次初始化。 cust7 的声明会导致错误。

    '' This code does not compile because Name is initialized twice.
    ' Dim cust7 = New Customer With {.Name = "Toni Poe", 
    '                                .City = "Louisville",
    '                                .Name = "Blue Yonder Airlines"}
    
  • 成员可用于初始化或其他字段。 如果在初始化某个成员之前访问该成员,如下面 cust8 的声明所示,将使用默认值。 请记住,当处理使用对象初始值设定项的声明时,首先会调用适当的构造函数。 之后,初始化初始值设定项列表中的各个字段。 在以下示例中,为 cust8 分配了 Name 的默认值,并在 cust9 中分配了一个初始化的值。

    Dim cust8 = New Customer With {.Name = .Name & ", President"}
    Dim cust9 = New Customer With {.Name = "Toni Poe", 
                                   .Title = .Name & ", President"}
    

    以下示例使用来自 cust3cust4 的参数化构造函数来声明和初始化 cust10cust11

    Dim cust10 = New Customer("Toni Poe") With {.Name = .Name & ", President"}
    ' --or--
    Dim cust11 As New Customer("Toni Poe") With {.Name = .Name & ", President"}
    
  • 对象初始值设定项可以被嵌套。 在以下示例中,AddressClass 是一个具有两个属性(CityState)的类,而 Customer 类具有一个 Address 属性(它是 AddressClass 的一个实例)。

    Dim cust12 = 
        New Customer With {.Name = "Toni Poe", 
                           .Address = 
                               New AddressClass With {.City = "Louisville", 
                                                      .State = "Kentucky"}}
    Console.WriteLine(cust12.Address.State)
    
  • 初始化列表不能为空。

  • 正在初始化的实例不能为 Object 类型。

  • 正在初始化的类成员不能为共享成员、只读成员、常量或方法调用。

  • 正在初始化的类成员不能被索引或限定。 以下示例引发编译器错误:

    '' Not valid.

    ' Dim c1 = New Customer With {.OrderNumbers(0) = 148662}

    ' Dim c2 = New Customer with {.Address.City = "Springfield"}

匿名类型

匿名类型使用对象初始值设定项来创建未显式定义和命名的新类型的实例。 相反,编译器会根据在对象初始值设定项列表中指定的属性生成类型。 由于未指定类型的名称,因此将其称为匿名类型。 例如,将以下声明与 cust6 的早期声明进行比较。

Dim cust13 = New With {.Name = "Toni Poe", 
                       .City = "Louisville"}

语法上的唯一区别是,在 New 之后没有为数据类型指定名称。 然而,发生的情况却完全不同。 编译器定义一个具有两个属性(NameCity)的新匿名类型,并使用指定的值创建该类型的实例。 类型推理断定示例中 NameCity 的类型为字符串。

注意

匿名类型的名称由编译器生成,并且可能因编译而异。 代码不应使用或依赖匿名类型的名称。

由于类型的名称不可用,因此不能使用 As 子句来声明 cust13。 必须推断其类型。 如果不使用后期绑定,这会将匿名类型的使用限制为局部变量。

匿名类型为 LINQ 查询提供关键支持。 有关在查询中使用匿名类型的详细信息,请参阅匿名类型Visual Basic 中的 LINQ 简介

关于匿名类型的注解

  • 通常,匿名类型声明中的所有或大部分属性都是键属性,通过在属性名前键入关键字 Key 来表示。

    
    Dim anonymousCust1 = New With {Key .Name = "Hugo Garcia", 
                                   Key .City = "Louisville"}
    

    有关键属性的详细信息,请参阅

  • 与命名类型一样,匿名类型定义的初始值设定项列表必须声明至少一个属性。

    Dim anonymousCust = New With {.Name = "Hugo Garcia"}
    
  • 当声明一个匿名类型的实例时,编译器会生成匹配的匿名类型定义。 属性的名称和数据类型来自实例声明,并由编译器包含在定义中。 属性没有提前命名和定义,因为它们将用于命名类型。 推断出其类型。 不能使用 As 子句指定属性的数据类型。

  • 匿名类型还可以通过其他几种方式建立其属性的名称和值。 例如,匿名类型属性可以同时采用变量的名称和值,也可采用另一个对象属性的名称和值。

    ' Create a variable, Name, and give it an initial value.
    Dim Name = "Hugo Garcia"
    
    ' Variable anonymousCust2 will have one property, Name, with 
    ' "Hugo Garcia" as its initial value.
    Dim anonymousCust2 = New With {Key Name}
    
    ' The next declaration uses a property from namedCust, defined
    ' in an earlier example. After the declaration, anonymousCust3 will
    ' have one property, Name, with "Terry Adams" as its value.
    Dim anonymousCust3 = New With {Key namedCust.Name}
    

    有关在匿名类型中定义属性的选项的详细信息,请参阅如何:推断匿名类型声明中的属性名和类型

另请参阅