在 Excel 中编写自定义函数——模拟 SUM 函数

来源:互联网 发布:淘宝信誉度查询网站 编辑:程序博客网 时间:2024/05/18 00:41

编写自定义函数是为了处理数据,如何向自定义的函数(UDF)传递待处理的数据就成为开发者要考虑的问题。

就一般意义上的函数来说,参数列表通常是参数个数固定,类型明确的,比如下面的声明:

Public Function MyFunc1(name As String, age As Integer) As String

但是 Excel 里的函数有它的特殊性。我们在工作表里编写公式的时候,往往并不提供具体的数字或字符串,比如("张三",23),作为参数。在 Excel 里,我们习惯用单元格或单元格范围的引用来传递参数,像上面的例子,我们在调用函数时的表达方式可能是 =MyFunc1(A1,B1)。就上面的声明而言,如果我们只允许传递单一的单元格引用给参数是正确的,Excel 知道单元格引用的数据类型。

但有的时候,对于函数的某个参数,我们希望既可以传递单一的单元格,也可以传递一块单元格范围,增加函数的灵活性,就像 =Sum(A1)=Sum(A1:A5) 都是可以的。这时候我们就不合适把参数声明为基本数据类型了,声明为 Excel 特有的数据类型 Range 就可以解决上面提到的问题,因为 Range 对象既可以是单一的单元格,也可以是一块单元格范围。

更进一步,如果我们希望参数列表是变长的呢?提供一个参数可以,提供两个三个也可以,参数的个数是任意的。

一种解决方法是用 Optional 关键词。带 Optional 关键词的参数不是必需的,我们可以给带 Optional 关键词的参数一个默认值,这样省略了该参数也没有什么关系了。

Public Function MyFunc2(name As String, Optional age As Integer =0) As String

但是用 Optional 关键词并不是真正的变长参数列表。我认为 Optional 关键词只是省去了用户的一些输入,在函数体内,参数的个数还是固定的。并且,如果我们希望提供的参数个数超出了定义的参数个数怎么办?Optional 是只能少不能多的,不是真正意义随心所欲的变长。

把参数声明为 Range 类型也是一种解决方法。Range 类型的参数可以是一个单元格,也可以是任意行列数的一块单元格。但是 Range 类型的参数也有个问题,我们传递单元格引用的时候是可行的,传递常数就会出错(Range 类型可以向下转换成基本类型,基本类型不能向上转换成 Range 类型)。我们希望在传递参数的数据类型上也保持一定的灵活性。

更贴近我们需求的解决方案是用 ParamArray 关键词。ParamArray 关键词允许我们传递任意个数的参数。并且,用 ParamArray 关键词声明的参数是 Variant 类型的数组,每个元素可以是各种数据类型。注意,ParamArray 关键词和 Optional 关键词是互斥的。

下面的例子是模拟 SUM 函数功能的自定义加总函数:

Function MySum(ParamArray numbers()) As DoubleDim i As IntegerDim j As IntegerDim k As IntegerDim argD As IntegerDim rtn As Doublertn = 0argD = UBound(numbers)For i = 0 To argD    If IsArray(numbers(i)) Then        If IsObject(numbers(i)) Then            For j = 1 To numbers(i).Rows.Count                For k = 1 To numbers(i).Columns.Count                    If IsNumeric(numbers(i)(j, k)) Then                        rtn = rtn + numbers(i)(j, k)                    End If                Next k            Next j        Else            For j = LBound(numbers(i)) To UBound(numbers(i))                rtn = rtn + numbers(i)(j)            Next j        End If    Else        If IsNumeric(numbers(i)) Then            rtn = rtn + numbers(i)        End If    End IfNext iMySum = rtnEnd Function

做几点说明,用 ParamArray 关键词声明的参数数组只返回最高一级的维度,看上去像是一维的。这是因为用 ParamArray 关键词声明的参数数组里面的元素可以是很不同的,不一定要是一个几乘几的整齐的矩阵。比如,我们上面自定义的 MySum 函数可以这样调用 =MySum(A2:D4,2,{1,2,3,4})

我们可以在代码里加入断点,然后从“Locals Window”查看 Numbers 这个数组的结构。如果我们尝试用 Numbers(i,j) 这样的表达式,反而会收到“Wrong number of dimensions”错误。

了解了用 ParamArray 关键词声明的参数数组的性质,就可以理解怎样遍历每个元素,并对每个元素进行不同的处理。

原创粉丝点击