使用具有现有属性的IF语句定义类属性

时间:2016-08-01 08:40:57

标签: vba excel-vba class excel

我有一个名为 cMilestones 的类,我有多个属性集,有些是Date,有些是Integer,有些是String

问题/挑战:我遇到困难,我想使用LetGet Property语句,但要使用已经定义的类属性(称为 CommittedDate UncommittedDate )。

PlanDate 财产条件

  1. If IsDate(CommittedDate) Then PlanDate = CommittedDate
  2. 其他:If IsDate(UnCommittedDate) Then PlanDate = UnCommittedDate
  3. 否则:以某种方式提出错误标志
  4. 到目前为止,我的 c里程碑类代码(工作部分)......

    Private pMilestoneName                  As String
    Private pCommittedDate                  As Date
    Private pUncommittedDate                As Date
    Private pPlanDate                       As Date
    Private pmsRow                          As Integer
    Private pmsRowPlan                      As Integer
    Private pmsRowAct                       As Integer
    Private pmsHgt_Up                       As Single
    Private pmsHgt_Down                     As Single
    
    ' --- Get/Let Methods ---
    
    Public Property Get MilestoneName() As String
        MilestoneName = pMilestoneName
    End Property
    
    Public Property Let MilestoneName(value As String)
        pMilestoneName = value
    End Property
    
    
    Public Property Get CommittedDate() As Date
        CommittedDate = pCommittedDate
    End Property
    
    Public Property Let CommittedDate(value As Date)
        If IsDate(value) Then
            pCommittedDate = value
        End If
    End Property
    
    
    Public Property Get UncommittedDate() As Date
        UncommittedDate = pUncommittedDate
    End Property
    
    Public Property Let UncommittedDate(value As Date)
        If IsDate(value) Then
            pUncommittedDate = value
        End If
    End Property
    

    还没有工作......

    ' ****** This is where I am not able to make it work *******
    Public Property Get PlanDate(pCommittedDate As Date) As Date
        PlanDate = pPlanDate
    End Property
    
    ' ****** This is where I am not able to make it work *******
    Public Property Let PlanDate(pCommittedDate As Date, pUncommittedDate As Date)
    'Public Sub PlanDate(pCommittedDate As Date, pUncommittedDate As Date)
    
        If IsDate(pCommittedDate) Then
            pPlanDate = pCommittedDate
        Else
            If IsDate(pUncommittedDate) Then
                pPlanDate = pUncommittedDate
            Else
                ' Milestone doesn't have Committed or Uncommitted plan >> raise Error Flag
    
            End If            
        End If
    
    End Property
    

    这是我的 Sub ,我使用数组来存储使用类对象的很多里程碑:

    Public Sub ReadMilestonesRange_toClass()    
    
    i = 0
    DataRow = FirstRow
    LastExistingMSRow = DataRow
    
    ' loop through all milestones in Column A to find the latest Row that has Milestone Name in it
    While DataRow <= LastMSRow
        Set ProjMilestones = New cMilestones
        ProjMilestones.MilestoneName = Cells(DataRow, 1)
        ProjMilestones.MSRow = DataRow
    
        ProjMilestones.CommittedDate = Cells(DataRow, 2)
        ProjMilestones.UncommittedDate = Cells(DataRow, 3)
    
        ' ****** Want to add the PlanDate to my cMilestones Class array ******
        ProjMilestones.PlanDate (ProjMilestones.UncommittedDate)
        ProjMilestones.ForecastDate = Cells(DataRow, 4)
        ProjMilestones.ActualDate = Cells(DataRow, 5)
    
        If ProjMilestones.MilestoneName <> "" Then
            ReDim Preserve ProjArrMilestones(0 To i)
            Set ProjArrMilestones(i) = ProjMilestones
            i = i + 1
            LastExistingMSRow = DataRow
    
        End If
        Set ProjMilestones = Nothing
    
        DataRow = DataRow + 1
    Wend
    MilestonesNum = LastExistingMSRow - FirstRow + 1 ' Total of Milestones in Milestone Table
    
          Set ProjMilestones = Nothing
    
    End Sub
    

4 个答案:

答案 0 :(得分:1)

pCommittedDatepUncommittedDate是类字段,因此它们在任何类实例中都可用,因此您不希望将它们作为参数传递给Property Get PlanDate()和{{1方法。

因此,您只需要针对Property Let PlanDate()值检查它们以查看是否已初始化

所以这样的代码:

0

这样您的代码就会运行,但Public Property Get PlanDate() As Date PlanDate = pPlanDate End Property Public Property Let PlanDate(value As Date) If pCommittedDate <> 0 Then 'if pCommittedDate is already "initialized" pPlanDate = pCommittedDate Else If pUncommittedDate <> 0 Then 'if pUncommittedDate is already "initialized" pPlanDate = pUncommittedDate Else ' Milestone doesn't have Committed or Uncommitted plan >> raise Error Flag End If End If End Property 是一个非常奇怪的属性,因为它的PlanDate访问器需要一个Let而根本没用!“ / p>

由于您似乎不希望类消费者设置value,只需将其转换为普通类字段:

PlanDate

在那里你摆脱了所有那些Public PlanDate As Date '... Public Property Get CommittedDate() As Date CommittedDate = pCommittedDate End Property Public Property Let CommittedDate(value As Date) pCommittedDate = value PlanDate = pCommittedDate '<--| set PlanDate as well End Property Public Property Get UncommittedDate() As Date UncommittedDate = pUncommittedDate End Property Public Property Let UncommittedDate(value As Date) pUncommittedDate = value If pCommittedDate = 0 Then PlanDate = pUncommittedDate '<--| set PlanDate only if 'pCommittedDate' is not initialized (changed pPlanDate to PlanDate) End Property ,因为你已经声明IsDate(value)所以在类消费者代码中无论如何都会发生错误,如果它试图设置任何value as Date值无效的

这里有一个可能的利用类,如上面的最后一个代码

Date

所以问题是:是否真的有必要让类消费者设置Sub main() Dim myvar As New cMilestones With myvar .CommittedDate = "1/1/2015" '<--| this will define 'PlanDate' as well .UncommittedDate = "31/12/2105" '<--| this will NOT redefine 'PlanDate', since 'CommittedDate' is already defined .PlanDate = "1/1/2016" '<--| this will redefine 'PlanDate'... End With End Sub

答案 1 :(得分:1)

如果需要使用数组将多个值传递给Property。

milestone.PlanDate = Arrray(#1/1/2016#, #2/1/2016#)

milestone.PlanDate = Range("A1:B1").Value
Public Property Let PlanDate(arrDates() As Variant)    
    If IsDate(arrDates(0)) Then
        pPlanDate = arrDates(0)
    Else
        If IsDate(arrDates(1)) Then
            pPlanDate = arrDates(1)
        Else
            ' Milestone doesn't have Committed or Uncommitted plan >> raise Error Flag

        End If
    End If

End Property

答案 2 :(得分:0)

在PlanDate的访问器中,你需要一个参数pCommitedDate - 但是你没有在你的身体中使用这个变量 - 因为它与解析这个参数完全无关。

Public Property Get PlanDate(pCommittedDate As Date) As Date
    PlanDate = pPlanDate
End Property

如果您想将pPlanDate分配到CommittedDateUnCommittedDate,只需将其添加到您的身体即可轻松完成此操作。

对于修饰符,请尝试使用Debug.Print输出来检查输入变量值。无论如何,你可以修改你的代码:

Public Property Let PlanDate(pCommittedDate As Date, pUncommittedDate As Date)

    If IsDate(pCommittedDate) Then
        pPlanDate = pCommittedDate
    ElseIf IsDate(pUncommittedDate) Then
        pPlanDate = pUncommittedDate
    Else
        ' Print to immediate-window
        Debug.Print "pCommittedDate or pUncommittedDate failed"
    End If      

End Property

答案 3 :(得分:0)

好的,让我们首先处理Rory非常有效的观点:

如果将变量声明为Date,则测试IsDate(var)将始终返回True,因为在初始化变量时会分配日期值。试试这段代码来证明:

Dim dat As Date

Debug.Print dat
Debug.Print IsDate(dat)

输出将是:

  

早上12点00分

     

当属性收到值时,有几种方法可以标记,也许最简单的方法就是设置一个布尔标志。像这样:

Private pDate1 As Date
Private pDate1IsSet As Boolean

Public Property Let Date1(val As Date)
    pDate1 = val
    pDate1IsSet = True
End Property

如果您运行以下模块代码

Dim oSchedule As clsSchedule

Set oSchedule = New clsSchedule
Debug.Print oSchedule.Date1IsSet & " " & oSchedule.Date1
oSchedule.Date1 = #1/21/2014#
Debug.Print oSchedule.Date1IsSet & " " & oSchedule.Date1

然后输出将是:

  

错误12:00:00 am。

     

True 21/01/2014

但是,在您的情况下,在其他两个日期设置器中设置pPlanDate变量可能更简单,如下所示:

Private pDate1 As Date
Private pDate2 As Date
Private pTheDate As Date

Public Property Let Date1(val As Date)
    pDate1 = val
    pTheDate = val
End Property

Public Property Let Date2(val As Date)
    pDate2 = val
    pTheDate = val
End Property

Public Property Get TheDate() As Date
    TheDate = pTheDate
End Property

最后,如果你确实需要测试是否没有设置日期,那么也许这应该是你班级的属性。您甚至可以优先考虑所需的日期,如下所示:

Private pDate1 As Date
Private pDate2 As Date
Private pTheDate As Date
Private pDateIsSet As Boolean

Public Property Let Date1(val As Date)
    pDate1 = val
    pTheDate = val
    pDateIsSet = True
End Property

Public Property Let Date2(val As Date)
    pDate2 = val
    If Not pDateIsSet Then
        pTheDate = val
        pDateIsSet = True
    End If
End Property

Public Property Get TheDate() As Date
    TheDate = pTheDate
End Property

Public Property Get DateIsSet() As Boolean
    DateIsSet = pDateIsSet
End Property

在我看来,这使得下面的代码更容易阅读,至少在我看来,它提供了一个包含特定于其目的的属性的类对象。您的课堂设计考虑因素可能会让您深思熟虑?

Dim oSchedule As clsSchedule

Set oSchedule = New clsSchedule
oSchedule.Date1 = #1/21/2014#
If oSchedule.DateIsSet Then
    Debug.Print oSchedule.TheDate
Else
    Debug.Print "No date"
End If