声明和构造值类型对象之间有区别吗?

时间:2009-10-02 15:40:40

标签: .net vb.net constructor value-type

我已经在.NET工作了一段时间了,但偶尔我仍然会对框架与我以前的C ++经验之间的差异感到困惑。

在.NET中,所有对象都是值类型或引用类型。引用类型在堆上分配,而值类型在堆栈上分配(无论如何,在当前的CLR实现中)。我明白了。但是,至少在VB.NET中,您仍然可以在值类型上定义构造函数。你可以这样做:

Public Structure Coordinates
    Public x As Integer
    Public y As Integer
    Public z As Integer

    Sub New(ByVal x As Integer, ByVal y As Integer, ByVal z As Integer)
        Me.x = x
        Me.y = y
        Me.z = z
    End Sub
End Structure

使用此代码,我可以编写Dim c As Coordinates然后自己访问c的成员,或者我可以编写Dim c As New Coordinates(10, 20, 30)。这两种方法有什么区别?显然new关键字没有在堆上分配对象,因为它是一个值类型。我只是不清楚值类型的构造函数是否仅仅是一种方便,还是它们实际上执行除执行之外的其他任何方法。

或许让我的观点更清楚:我可以轻松删除上述代码中New的定义,但我仍然可以这样做:

Dim c1 As Coordinates
Dim c2 As New Coordinates

这两行有什么不同吗?


编辑:Guffa指出声明和构建相同。以下代码演示了这一点:

For i As Integer = 1 To 3
    Dim c1 As Coordinates
    Dim c2 As New Coordinates

    c1.x += 1
    c2.x += 1

    Console.WriteLine("c1.x = {0}, c2.x = {1}", c1.x, c2.x)
Next

' output: '
' c1.x = 1, c2.x = 1 '
' c1.x = 2, c2.x = 1 '
' c1.x = 3, c2.x = 1 '

因此,在涉及迭代的场景中,表示值类型的局部变量不会在堆栈上重新分配;他们留下来。我使用普通的旧整数看了同样的场景,发现了同样的行为:

For i As Integer = 1 To 3
    Dim x As Integer
    Dim y As New Integer

    x += 1
    y += 1

    Console.WriteLine("x = {0}, y = {1}", x, y)
Next

' output: '
' x = 1, y = 1 '
' x = 2, y = 1 '
' x = 3, y = 1 '

3 个答案:

答案 0 :(得分:3)

在声明中使用New关键字,如下所示:

Dim c2 As New Coordinates

只是一个快捷方式:

Dim c2 As Coordinates = New Coordinates()

为结构自动创建无参数构造函数,它只返回一个值,所有属性都设置为默认值(即所有字节都清零),功能相当于:

Public Sub New()
   x = 0
   y = 0
   z = 0
End Sub

在VB中,当您使用方法时,所有局部变量都会被初始化,因此在没有New关键字的情况下声明的变量c1也将被清零。在您多次执行语句之前,差异是不可见的:

For i As Integer = 1 to 3
   Dim c1 As Coordinates
   Dim c2 As New Coordinates
   c1.x += 1
   c2.x += 1
   Console.WriteLine("c1.x = {0}, c2.x = {1}", c1.x, c2.x)
Next

输出:

c1.x = 1, c2.x = 1
c1.x = 2, c2.x = 1
c1.x = 3, c2.x = 1

c1变量只初始化一次,而每次执行语句时都会初始化c2变量。

由于结构值可以在不首先调用构造函数的情况下存在,因此结构构造函数大多是初始化结构的便捷方式。它比创建结构值的静态方法更整洁,但它的工作原理基本相同:

Public Shared Function Create(ByVal x As Integer, ByVal y As Integer, ByVal z As Integer) As Coordinates
   Dim item As Coordinates
   item.x = x
   item.y = y
   item.z = z
   Return item
End Function

Dim c3 As Coordinates = Coordinates.Create(1, 2, 3)

答案 1 :(得分:2)

结构总是有一个默认的(无参数)构造函数(声明它是一个错误)。

for VB.Net(EDIT)

它是一样的;),见here

代表C#:

Coordinates c1;Coordinates c2 = New Coordinates();之间的区别在于,对于第一个结构字段保持未分配状态,并且在初始化所有字段之前无法使用该对象。第二个初始化struct对象中的所有字段。

有关详细信息,请转到here,它非常详细。

答案 2 :(得分:1)

在VB.Net中,

Dim c1 As Coordinates
Dim c2 As New Coordinates

做同样的事情。在C#中,尝试使用c1.X会产生编译器(未分配)错误,而c2.X将为0。

根据VB规则,局部变量默认设置为0(或0.0或false或...),在C#中,它们被视为未分配。

构造函数的规则对于结构和类是不同的,您不能添加:

 Sub New()
    Me.x = 1
    Me.y = 2
    Me.z = 3
 End Sub

因为这个构造函数是'保留'。