将数组传递给ParamArray

时间:2013-12-26 10:24:59

标签: vba parameters parameter-passing paramarray

是否可以将数组的所有元素传递给ParamArray?

例如,我想将ParamArray传递给另一个ParamArray:

Sub test()
    p1 "test", "banane", "birne"
End Sub

Sub p1(ParamArray keys() As Variant)
    p2 keys 'should be the same as: p2 "test", "banane", "birne"
End Sub

Sub p2(ParamArray keys() As Variant)
    Dim key As Variant
    For Each key In keys
        Debug.Print key 'Run-time error '13' Type mismatch (key is an array)
    Next key
End Sub

在这种情况下,p2的ParamArray不包含keys的元素,但它获取数组对象keys。因此,如果传递数组,我必须检查:

Sub test()
    p1 "test", "banane", "birne"
    p2 "test", "banane", "birne"
End Sub

Sub p1(ParamArray keys() As Variant)
    p2 keys
End Sub

Sub p2(ParamArray params() As Variant)
    Dim keys As Variant
    If IsArray(params(0)) Then
        keys = params(0)
    Else
        keys = params
    End If

    Dim key As Variant
    For Each key In keys
        Debug.Print key
    Next key
End Sub

但与Java相比,这是尴尬的:

public class VarArgs {

    public static void main(String[] args) {
        p1("test", "banane", "birne");
        p2("test", "banane", "birne");

        String[] array = {"test", "banane", "birne"};
        p1(array);
        p2(array);
    }

    public static void p1(String... strings) {
        p2(strings);
    }

    public static void p2(String... strings) {
        for (String string : strings) {
            System.out.println(string);
        }
    }

}

在Java中,我不必区分。但这在VBA中可能是不可能的。

感谢您的帮助,
迈克尔

7 个答案:

答案 0 :(得分:6)

将ParamArray参数传递给另一个需要ParamArray参数的函数(委托ParamArray参数)。 我需要委托一个类型的函数:strf(str as string, ParamArray args() as Variant) as String在ParamArray中的其他函数中接收的参数直接传递而不显式写入。 我发现的限制是:

  1. ParamArray()它只能传递给另一个需要ParamArray的函数。
  2. ParamArray在元素0处作为Variant()
  3. 收到
  4. 当第二个功能接收时,它会增加深度 我没有找到任何令人满意的解决方案,但我编写了一个功能完美的函数,撤消了添加的深度级别并返回了带有参数的向量。
  5. 代码:

    Option Explicit
    Option Base 1
    
    Public Sub PrAr1(ParamArray pa1() As Variant)
    Dim arr() As Variant
      arr = fn.ParamArrayDelegated(pa1)
      PrAr2 pa1
    End Sub
    
    Public Sub PrAr2(ParamArray pa2() As Variant)
    Dim i As Integer, arrPrms() As Variant
      arrPrms = fn.ParamArrayDelegated(pa2)
      For i = 0 To UBound(arrPrms)
        Debug.Print s.strf("i: %0 prm: %1 ", i, arrPrms(i))
      Next i
      PrAr3 pa2
    End Sub
    
    Public Sub PrAr3(ParamArray pa3() As Variant)
    Dim i As Integer, arrPrms() As Variant
      arrPrms = fn.ParamArrayDelegated(pa3)
      For i = 0 To UBound(arrPrms)
        Debug.Print s.strf("i: %0 prm: %1 ", i, arrPrms(i))
      Next i
    End Sub
    
    Public Function ParamArrayDelegated(ParamArray prms() As Variant) As Variant
    Dim arrPrms() As Variant, arrWrk() As Variant
    'When prms(0) is Array, supposed is delegated from another function
      arrPrms = prms
      Do While VarType(arrPrms(0)) >= vbArray And UBound(arrPrms) < 1
        arrWrk = arrPrms(0)
        arrPrms = arrWrk
      Loop
      ParamArrayDelegated = arrPrms
    End Function
    

答案 1 :(得分:4)

您可以在第二次通话时将其转换为Variant

Sub test()
    p1 "test", "banane", "birne"
End Sub

Sub p1(ParamArray keys() As Variant)
    p2 CVar(keys) '<--| pass it as a Variant
End Sub

Sub p2(keys As Variant) '<--| accept a Variant argument
    Dim key As Variant

    For Each key In keys
        Debug.Print key
    Next key
End Sub

答案 2 :(得分:2)

这是我的解决方案。请注意,它的一个限制是您只能将一个(Variant)数组参数传递给ParamArray参数集。可能它可以推广到处理多个传递的数组,但我还没有遇到这种需要。

Option Explicit

Sub test()
    p1 "test", "banane", "birne"
    p2 "test", "banane", "birne"
End Sub


Sub p1(ParamArray keys() As Variant)
    Dim TempKeys As Variant

    TempKeys = keys 'ParamArray isn't actually a standard Variant array, so you have to copy
                    'it to one in order for the added test/workaround in p2 to not crash
                    'Excel.

    p2 TempKeys 'should be the same as: p2 "test", "banane", "birne"
End Sub

Sub p2(ParamArray keys() As Variant)
    Dim key As Variant

    If IsArray(keys(0)) Then keys = keys(0) 'Set this routine's ParamArray parameter to be
                                            'the array of its first element.

    For Each key In keys
        Debug.Print key
    Next key
End Sub

答案 3 :(得分:1)

尝试:

Sub p2(ParamArray keys() As Variant) 
dim myKey as Variant  
 If IsArray(keys(0)) Then
        myKey = keys(0)
    Else
        myKey = keys()
 End If

...
end sub

答案 4 :(得分:0)

Sub test()
    p1 "test", "banane", "birne"
End Sub

Sub p1(ParamArray keys() As Variant)
    p2 keys
End Sub

Sub p2(ParamArray keys() As Variant)
    Dim key As Variant
    For Each key In keys
        Debug.Print key(0) '<- Give an Index here.
    Next key
End Sub

答案 5 :(得分:0)

我最强烈的需求之一是能够将 ParamArray values() As Variant 变成 String()

根据 OPs 问题,我还需要能够将其他函数转发到此函数,其中其他函数有一个 ParamArray,在该函数可以之前,它也需要转换为 String()继续处理。

这里的解决方案包括一个健壮的函数来安全地返回数组的大小:

Public Function f_uas_astrFromParamArray( _
    ParamArray pr_avarValues() As Variant _
) As String()
  Dim astrResult() As String
  
  Dim avarTemp() As Variant
  Dim lngSize As Long
  Dim lngUBound As Long
  Dim lngIndex As Long
  
  If (IsMissing(pr_avarValues) = False) Then
    If (IsArray(pr_avarValues(0)) = True) Then
      avarTemp = pr_avarValues(0)
    Else
      avarTemp = pr_avarValues
    End If
    lngSize = f_lngArraySize(avarTemp)
    If (lngSize > 0) Then
      lngUBound = lngSize - 1
      ReDim astrResult(0 To lngUBound)
      For lngIndex = 0 To lngUBound
        astrResult(lngIndex) = CStr(avarTemp(lngIndex))
      Next lngIndex
    End If
  End If
  
  f_uas_astrFromParamArray = astrResult
End Function

'Return Value:
'   -1 - Not an Array
'    0 - Empty
'  > 0 - Defined
Public Function f_ua_lngArraySize( _
    ByRef pr_avarValues As Variant _
  , Optional ByVal pv_lngDimensionOneBased As Long = 1 _
) As Long
  Dim lngSize As Long: lngSize = -1 'Default to not an Array
  Dim lngLBound As Long
  Dim lngUBound As Long
  
  On Error GoTo Recovery
  
  If (IsArray(pr_avarValues) = True) Then
    lngSize = 0 'Move default to Empty
    lngLBound = LBound(pr_avarValues, pv_lngDimensionOneBased)
    lngUBound = UBound(pr_avarValues, pv_lngDimensionOneBased)
    If (lngLBound <= lngUBound) Then
      lngSize = lngUBound - lngLBound + 1 'Non-Empty, so return size
    End If
  End If
  
NormalExit:
  f_ua_lngArraySize = lngSize
  Exit Function
  
Recovery:
  GoTo NormalExit
End Function

答案 6 :(得分:-2)

paramArrays很奇怪,但你可以使用普通的数组,它可以正常工作

 Sub test()
    Dim a As Variant: a = Array("test", "banane", "birne")
    p1 a
End Sub

Sub p1(keys As Variant)
    p2 keys
End Sub

Sub p2(keys As Variant)
    Dim key As Variant
    For Each key In keys
        Debug.Print key
    Next key
End Sub