【问题标题】:How to handle full-column ranges in UDF?如何处理 UDF 中的全列范围?
【发布时间】:2016-06-19 22:36:43
【问题描述】:

我使用 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

【问题讨论】:

    标签: .net vb.net excel optimization excel-dna


    【解决方案1】:

    一次性从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 来获取工作表的使用范围,并将其与您的 ExcelReference 相交。一个缺点是这需要将您的函数标记为IsMacroType=true,这(连同AllowReference=true)具有使您的函数易变的副作用。

    显示如何执行此操作的代码在这里:https://gist.github.com/govert/e66c5462901405dc96aab8e77abef24c

    【讨论】:

    • 再次感谢!我使用该 Gist 来升级我的功能:我已经同时使用了 IsMacroTypeAllowReference,因此代码确实非常适合! :D
    猜你喜欢
    • 1970-01-01
    • 2016-07-03
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多