Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel VBA:检查可选参数_Excel_Vba_Optional Parameters - Fatal编程技术网

Excel VBA:检查可选参数

Excel VBA:检查可选参数,excel,vba,optional-parameters,Excel,Vba,Optional Parameters,我有两个sub,希望将值从一个传递到另一个 Option Explicit Sub Test() Call HandleInput(ActiveSheet.Range("A1:C4"), 4, 2) End Sub Sub HandleInput(rng As Range, rowNumber As Long, colNumber As Long) Debug.Print rng.Cells(rowNumber, colNumber).Value End Sub 但是,有时

我有两个sub,希望将值从一个传递到另一个

Option Explicit

Sub Test()
    Call HandleInput(ActiveSheet.Range("A1:C4"), 4, 2)
End Sub

Sub HandleInput(rng As Range, rowNumber As Long, colNumber As Long)
    Debug.Print rng.Cells(rowNumber, colNumber).Value
End Sub
但是,有时我希望在相同的范围内应用相同的例程,但使用不同的行号和列号。我可以用新的值再次调用sub,现在这似乎是最简单的选择,但我仍然想知道是否有一种聪明的方法可以使用HandleInput中的可选参数来处理它:

这让我想知道:

我是否可以告诉VBA,如果提供了rowNumber2,还需要传递colNumber2的值?我知道我可以尝试使用IsMissing并将数据类型切换为Variant:

这需要大量的if语句,如果不是IsMissingcolNumber2,也需要相反方向的if语句。如果将两个以上的变量联系在一起,情况只会变得更糟。当缺少一个值时,我尝试作为解决方法的任何计算都会导致错误类型不匹配,例如,我尝试了:

If IsError(rowNumber2 * colNumber2) Then
   MsgBox "Error, please supply both rowNumber2 and colNumber2"
End If
这有本机功能吗?我提出的唯一解决方案是提供我知道不会自然出现的默认值:

Sub HandleInput(rng As Range, rowNumber As Long, colNumber As Long, Optional rowNumber2 As Long = -100, _
Optional colNumber2 As Long = -100, Optional rowNumber3 As Long = -100, Optional colNumber3 As Long = -100)

     If rowNumber2 = -100 Or colNumber2 = -100 Then
        MsgBox "Please enter a value for both rowNumber2 and colNumber2."
        End
    End If
End Sub

你可以用一个范围来处理整件事,并检查进线阵列

Sub HandleInput(rng As Range, ParamArray RCPairs() As Variant)

    If UBound(RCPairs) < 1 Then
        Err.Raise 513, "HandleInput", "Please enter at least one pair of RowNumber, ColNumber."
    ElseIf UBound(RCPairs) Mod 2 = 0 Then
        Err.Raise 513, "HandleInput", "Please enter a value for both RowNumber and ColNumber."
    End If

    ' ...

End Sub

注意:我将您的MsgBox设置为“结束”,以引发错误,因此您的调用代码可以决定如何处理错误。顺便说一句,使用End是不明智的,

您可以使用范围来处理整个文件,并检查输入阵列

Sub HandleInput(rng As Range, ParamArray RCPairs() As Variant)

    If UBound(RCPairs) < 1 Then
        Err.Raise 513, "HandleInput", "Please enter at least one pair of RowNumber, ColNumber."
    ElseIf UBound(RCPairs) Mod 2 = 0 Then
        Err.Raise 513, "HandleInput", "Please enter a value for both RowNumber and ColNumber."
    End If

    ' ...

End Sub

注意:我将您的MsgBox设置为“结束”,以引发错误,因此您的调用代码可以决定如何处理错误。顺便说一句,使用End是不明智的,

魔法默认值是个坏主意

你需要一个代表两个值的概念,这两个值需要始终结合在一起——这听起来很像需要某种封装两个值的对象;我将使用nuclear强类型选项,并添加两个新的类模块——首先是一些通用ITuple接口:

'@Interface
Option Explicit

Public Property Get Item1() As Variant
End Property

Public Property Get Item2() As Variant
End Property

Public Function ToString() As String
End Function
然后是实现它的RangeLocation类:

'@PredeclaredId 'see https://github.com/rubberduck-vba/Rubberduck/wiki/VB_Attribute-Annotations
Option Explicit
Implements ITuple

Private Type TInternal
    RowIndex As Long
    ColumnIndex As Long
End Type

Private this As TInternal

Public Function Create(ByVal atRow As Long, ByVal atColumn As Long) As ITuple
    Dim result As RangeLocation
    Set result = New RangeLocation
    result.RowIndex = atRow
    result.ColumnIndex = atColumn
    Set Create = result
End Function

Public Property Get RowIndex() As Long
    RowIndex = this.RowIndex
End Property

Public Property Let RowIndex(ByVal value As Long)
    If value <= 0 Then Err.Raise 5
    this.RowIndex = value
End Property

Public Property Get ColumnIndex() As Long
    ColumnIndex = this.ColumnIndex
End Property

Public Property Let ColumnIndex(ByVal value As Long)
    If value <= 0 Then Err.Raise 5
    this.ColumnIndex = value
End Property

Private Property Get ITuple_Item1() As Variant
    ITuple_Item1 = this.RowIndex
End Property

Private Property Get ITuple_Item2() As Variant
    ITuple_Item2 = this.ColumnIndex
End Property

Private Function ITuple_ToString() As String
    ITuple_ToString = "R" & this.RowIndex & "C" & this.ColumnIndex
End Function
这意味着我们也可以这样做:

Public Sub DoSomething(ByVal source As Range, ParamArray values() As Variant)
    Dim i As Long
    For i = LBound(values) To UBound(values)

        Dim location As ITuple
        Set location = values(i)

        On Error Resume Next
        Debug.Print source.Cells(location.Item1, location.Item2).Value
        If Err.Number <> 0 Then Debug.Print "Location " & location.ToString & " is outside the specified source range."
        On Error GoTo 0

    Next
End Sub

如果调用方尝试执行RangeLocation.Create0,-12,则会出现运行时错误,因为该属性允许RangeLocation类的成员不允许负值,甚至不会调用DoSomething。

魔法默认值是个坏主意

你需要一个代表两个值的概念,这两个值需要始终结合在一起——这听起来很像需要某种封装两个值的对象;我将使用nuclear强类型选项,并添加两个新的类模块——首先是一些通用ITuple接口:

'@Interface
Option Explicit

Public Property Get Item1() As Variant
End Property

Public Property Get Item2() As Variant
End Property

Public Function ToString() As String
End Function
然后是实现它的RangeLocation类:

'@PredeclaredId 'see https://github.com/rubberduck-vba/Rubberduck/wiki/VB_Attribute-Annotations
Option Explicit
Implements ITuple

Private Type TInternal
    RowIndex As Long
    ColumnIndex As Long
End Type

Private this As TInternal

Public Function Create(ByVal atRow As Long, ByVal atColumn As Long) As ITuple
    Dim result As RangeLocation
    Set result = New RangeLocation
    result.RowIndex = atRow
    result.ColumnIndex = atColumn
    Set Create = result
End Function

Public Property Get RowIndex() As Long
    RowIndex = this.RowIndex
End Property

Public Property Let RowIndex(ByVal value As Long)
    If value <= 0 Then Err.Raise 5
    this.RowIndex = value
End Property

Public Property Get ColumnIndex() As Long
    ColumnIndex = this.ColumnIndex
End Property

Public Property Let ColumnIndex(ByVal value As Long)
    If value <= 0 Then Err.Raise 5
    this.ColumnIndex = value
End Property

Private Property Get ITuple_Item1() As Variant
    ITuple_Item1 = this.RowIndex
End Property

Private Property Get ITuple_Item2() As Variant
    ITuple_Item2 = this.ColumnIndex
End Property

Private Function ITuple_ToString() As String
    ITuple_ToString = "R" & this.RowIndex & "C" & this.ColumnIndex
End Function
这意味着我们也可以这样做:

Public Sub DoSomething(ByVal source As Range, ParamArray values() As Variant)
    Dim i As Long
    For i = LBound(values) To UBound(values)

        Dim location As ITuple
        Set location = values(i)

        On Error Resume Next
        Debug.Print source.Cells(location.Item1, location.Item2).Value
        If Err.Number <> 0 Then Debug.Print "Location " & location.ToString & " is outside the specified source range."
        On Error GoTo 0

    Next
End Sub

如果调用方尝试执行RangeLocation.Create0,-12,则会出现运行时错误,因为该属性允许RangeLocation类的成员不允许负值,甚至不会调用DoSomething。

您也可以使用数组作为参数来查看传递参数时的概念。然后养成习惯,用这些关键字中的一个来标记每个参数。@Peter T就可以了,谢谢你的提示。你也可以使用数组作为参数来检查传递参数时的概念。然后养成习惯,用这些关键字中的一个标记每个参数。@Peter T会的,谢谢你的提示
Dim source As Range
Set source = ActiveSheet.Range("A1:C4")

DoSomething source, _
    RangeLocation.Create(4, 2), _
    RangeLocation.Create(1, 1), _
    RangeLocation.Create(2, 2)
    '...