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

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

声明

命名和匿名类型的实例声明看起来几乎相同,但它们的效果并不相同。 每个类别都有自己的功能和限制。 以下示例演示了使用对象初始值设定项列表声明和初始化命名类 Customer实例的便捷方法。 请注意,类的名称在关键字 New后面指定。

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

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

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

这两个声明的要求和结果不同。 对于 namedCustCustomer 具有 Name 属性的类必须已存在,并且声明将创建该类的实例。 对于 anonymousCust,编译器定义一个新类,该类具有一个属性、一个调用 Name的字符串,并创建该类的新实例。

命名类型

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

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

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

或者,可以使用以下代码获取相同的结果:

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

其中每个声明都等效于以下示例,该示例使用无参数构造函数创建对象Customer,然后使用语句指定和Name属性City的初始值With

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 变量声明中的子句。 变量的数据类型是从赋值创建的对象的类型推断的。 在下面的示例中,类型 cust6Customer.

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 的声明所示,将使用默认值。 请记住,当处理使用对象初始值设定项的声明时,首先会调用相应的构造函数。 之后,将依次初始化初始化列表中的每个字段。 在以下示例中,Name 的默认值被赋给了 cust8,而有初始化值被赋给 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}
    

    有关在匿名类型中定义属性的选项的详细信息,请参阅 How to: Infer Property Names and Types in Anonymous Type Declarations.

另请参阅