如何处理 UDF 中的全列范围?
How to handle full-column ranges in UDF?
我使用 Excel DNA 为 Excel 开发了一个插件。我声明了一个接受范围作为输入的 UDF,将 ExcelReference
转换为 Range
并使用 GetEnumerator
中的枚举器收集 List
中的所有单元格值以进行进一步处理和然后将输出写入另一个范围。
作为测试,我尝试将一整列传递给函数 (A:A
),但一切都冻结了,因为枚举器在最后一个有值的单元格之后继续枚举空单元格。
有没有更快的方法来检测整列范围并获取其所有不为空的单元格?
目前我正在使用这段代码,但在上述情况下速度非常慢。
Dim ue = inputRange.GetEnumerator
Dim L As New List(Of String)
Do
If ue.MoveNext Then
Dim c As Range = ue.Current
Dim V As String = c.FormulaLocal
If String.IsNullOrWhiteSpace(V) Then Continue Do
L.Add(V)
Else
Exit Do
End If
Loop
我将使用以下解决方法,但我想从根本上防止这种情况。
Dim ue = inputRange.GetEnumerator
Dim counter as integer=0
Dim L As New List(Of String)
Do
If counter>10 Then Exit Do
If ue.MoveNext Then
Dim c As Range = ue.Current
Dim V As String = c.FormulaLocal
If String.IsNullOrWhiteSpace(V.Trim) Then
counter = counter + 1
Continue Do
End If
L.Add(V)
Else
Exit Do
End If
Loop
一次性从 ExcelReference
获取所有值比获取 COM Range
对象要快得多。
从参数中删除 AllowReference=true
(然后您将直接获取值)或从 ExcelReference
:
中获取值
object value = inputRef.GetValue();
if (value is object[,])
{
object[,] valueArr = (object[,])value;
int rows = valueArr.GetLength(0);
int cols = valueArr.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
object val = valueArr[i,j];
// Do more here...
}
}
}
如果单元格为空,您获得的对象将是 ExcelEmpty 类型。如果您对空单元格不感兴趣,可以忽略这些。
另一种方法是使用 C API 获取 sheet 的使用范围,并将其与 ExcelReference
相交。一个缺点是这需要将您的函数标记为 IsMacroType=true
,这(与 AllowReference=true
一起)具有使您的函数易变的副作用。
此处显示如何执行此操作的代码:https://gist.github.com/govert/e66c5462901405dc96aab8e77abef24c
我使用 Excel DNA 为 Excel 开发了一个插件。我声明了一个接受范围作为输入的 UDF,将 ExcelReference
转换为 Range
并使用 GetEnumerator
中的枚举器收集 List
中的所有单元格值以进行进一步处理和然后将输出写入另一个范围。
作为测试,我尝试将一整列传递给函数 (A:A
),但一切都冻结了,因为枚举器在最后一个有值的单元格之后继续枚举空单元格。
有没有更快的方法来检测整列范围并获取其所有不为空的单元格?
目前我正在使用这段代码,但在上述情况下速度非常慢。
Dim ue = inputRange.GetEnumerator
Dim L As New List(Of String)
Do
If ue.MoveNext Then
Dim c As Range = ue.Current
Dim V As String = c.FormulaLocal
If String.IsNullOrWhiteSpace(V) Then Continue Do
L.Add(V)
Else
Exit Do
End If
Loop
我将使用以下解决方法,但我想从根本上防止这种情况。
Dim ue = inputRange.GetEnumerator
Dim counter as integer=0
Dim L As New List(Of String)
Do
If counter>10 Then Exit Do
If ue.MoveNext Then
Dim c As Range = ue.Current
Dim V As String = c.FormulaLocal
If String.IsNullOrWhiteSpace(V.Trim) Then
counter = counter + 1
Continue Do
End If
L.Add(V)
Else
Exit Do
End If
Loop
一次性从 ExcelReference
获取所有值比获取 COM Range
对象要快得多。
从参数中删除 AllowReference=true
(然后您将直接获取值)或从 ExcelReference
:
object value = inputRef.GetValue();
if (value is object[,])
{
object[,] valueArr = (object[,])value;
int rows = valueArr.GetLength(0);
int cols = valueArr.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
object val = valueArr[i,j];
// Do more here...
}
}
}
如果单元格为空,您获得的对象将是 ExcelEmpty 类型。如果您对空单元格不感兴趣,可以忽略这些。
另一种方法是使用 C API 获取 sheet 的使用范围,并将其与 ExcelReference
相交。一个缺点是这需要将您的函数标记为 IsMacroType=true
,这(与 AllowReference=true
一起)具有使您的函数易变的副作用。
此处显示如何执行此操作的代码:https://gist.github.com/govert/e66c5462901405dc96aab8e77abef24c