1

我正在玩以下内容:

Public MustInherit Class TempTable
    Public Sub New()
        For Each f As FieldInfo In Me.GetType().GetFields
            Dim l As TypedLeaf = CType(f.GetValue(Me), TypedLeaf)
            Console.WriteLine(l.Name)
        Next
    End Sub
End Class

Public Class JMTempTable
    Inherits TempTable

    Public KeyIndex As New TypedLeaf(Me, "KeyIndex", OQL.Type.AUTONUMBER)
    Public Debit As New TypedLeaf(Me, "Debit", OQL.Type.DECIMAL(16, 2))

    Public Sub New()
        MyBase.New()
    End Sub
End Class

但对检索到的值没有任何结果。原因似乎是派生类的字段直到基类的构造函数被调用之后才被初始化......如果我这样做的话,会使事情变得更加复杂:

Public Class JMTempTable
    Inherits TempTable

    Public KeyIndex As TypedLeaf
    Public Debit As TypedLeaf

    Public Sub New()
        KeyIndex = New TypedLeaf(Me, "KeyIndex", OQL.Type.AUTONUMBER)
        Debit = New TypedLeaf(Me, "Debit", OQL.Type.DECIMAL(16, 2))

        MyBase.New()
    End Sub
End Class

编译器会抱怨必须在派生类的构造函数的第一行调用基类构造函数...

有没有办法可以延迟基类构造函数的运行,直到派生类的字段被初始化之后?

4

2 回答 2

1

这是一种方法(也许方法):

Public MustInherit Class TempTable
    Public Sub New()
        Initialize()
        For Each f As FieldInfo In Me.GetType().GetFields
            Dim l As TypedLeaf = CType(f.GetValue(Me), TypedLeaf)
            Console.WriteLine(l.Name)
        Next
    End Sub

    Protected MustOverride Sub Initialize()
End Class

Public Class JMTempTable
    Inherits TempTable

    Public KeyIndex As TypedLeaf()
    Public Debit As TypedLeaf()

    Public Sub New() ' Optional block. You don't have to explicitly define a default constructor.
        MyBase.New()
    End Sub

    Protected Overrides Sub Initialize()
        KeyIndex = New TypedLeaf(Me, "KeyIndex", OQL.Type.AUTONUMBER)
        Debit = New TypedLeaf(Me, "Debit", OQL.Type.DECIMAL(16, 2))
    End Sub
End Class

抽象Initialize()方法强制继承者拥有一个名为 的方法Initialize()。调用时会隐式调用此方法MyBase.New()。这意味着您现在可以将初始化逻辑移出构造函数并移入Initialize()方法中以获得您正在寻找的效果。

于 2012-05-12T21:16:42.417 回答
1

这在托管语言中通常是众所周知的行为。令人惊讶的是,我在 VB.NET 语言规范中没有明确提到它,所以我必须自己解释一下。

CLI 直接支持字段初始化器,但它们不足以支持您的字段。他们只能存储简单的数据,思考值类型。初始化引用类型,例如 TypedLeaf 类,需要执行代码。并且代码不能存储在字段初始化器中,它只能出现在方法内部。

因此,VB.NET 编译器通过字段初始化表达式移动到下一个逻辑位置,即类构造函数来解决该限制。这是完全自动的,它实际上会重写您的构造函数,以防您自己提供一个,并根据需要注入的运算符调用。

现在有一个选择,它可以在基类构造函数调用之前之后移动这些调用。您已经知道所做的选择,它发生. 理由是字段初始化程序不应该能够观察尚未初始化的基类成员。您尝试解决方法实际上是非常英勇的编译器编写技巧,它实际上检查了是否首先调用了基本构造函数。

不幸的是,您发现如果它发生在基本构造函数调用之前,您实际上会更快乐。这是有道理的,但不幸的是,这是不允许的,语言设计者放下了脚并宣称“我们只支持一种方法来做到这一点”。公平的电话,这样的基础需要是可预测的。

解决方法很简单。只需在您的基类中放置一个受保护的方法,例如“初始化”,然后将您现在在构造函数中的代码移动到该方法。在派生类构造函数中只需调用该方法。构造函数重写确保基础构造函数调用在前,字段初始化代码在后,方法调用在第三。减去 33.3 分,因为必须记住进行该调用,因此添加代码以在您看到 Nothing 时抛出 InvalidOperationException。

于 2012-05-12T21:57:31.440 回答