C# 当名称重复时,在Excel工作簿中按字符串获取命名范围

C# 当名称重复时,在Excel工作簿中按字符串获取命名范围,c#,excel,named-ranges,C#,Excel,Named Ranges,更详细地说,假设我的工作簿中有两个命名范围。两个命名范围具有相同的名称(比如“myName”),但一个范围为Sheet1,另一个范围为工作簿 给定命名范围的名称(字符串),我想获取工作簿级别的命名范围 如果使用本机调用:wb.Names.Item(“myName”),则返回工作表范围的命名范围 如果改为:wb.Names.Item(“Sheet1!myName”),则显然返回工作表范围的名称范围。我发现我可以使用它来指定特定于工作表的工作表,但不能指定工作簿 我是否可以指定我想要工作簿范围的工作

更详细地说,假设我的工作簿中有两个命名范围。两个命名范围具有相同的名称(比如“myName”),但一个范围为Sheet1,另一个范围为工作簿

给定命名范围的名称(字符串),我想获取工作簿级别的命名范围

如果使用本机调用:
wb.Names.Item(“myName”)
,则返回工作表范围的命名范围

如果改为:
wb.Names.Item(“Sheet1!myName”)
,则显然返回工作表范围的名称范围。我发现我可以使用它来指定特定于工作表的工作表,但不能指定工作簿

我是否可以指定我想要工作簿范围的工作簿

我的解决方法目前正在迭代所有名称的列表,并比较.Name属性以获取名为Range的工作簿范围。这是因为.Name属性将“Sheet1!”附加到工作表范围的命名范围。然而,这是非常昂贵的,我想避免它。

当我们(JKP和我自己)在撰写本文时,我们专门为重复的全局/本地名称添加了一个过滤器和警告消息,因为您提到的这种Excel对象模型行为会导致难以检测的错误。

因此,我的建议是永远不要使用重复的全局/本地名称。

我们使用代码来检测名称是否与本地名称处于活动状态,然后根据需要切换工作表。我们用于查找全局名称的本地版本的优化VBA代码是这样的:它相当快,除非您有数万个名称-

    Function FindNameLocal(oSheet As Worksheet, sName As String) As Name
        Dim oName As Name
        Dim strLocalName As String
        Dim strLocalNameNoQuote
        Dim strName As String
        Set FindNameLocal = Nothing
        If Len(sName) > 0 And Not oSheet Is Nothing And oSheet.Names.Count > 0 Then
            On Error Resume Next
            strLocalName = "'" & oSheet.Name & "'!" & sName
            strLocalNameNoQuote = oSheet.Name & "!" & sName
            Set FindNameLocal = oSheet.Names(strLocalName)
            If Err <> 0 Or (FindNameLocal.NameLocal <> strLocalName And FindNameLocal.NameLocal <> strLocalNameNoQuote) Then
                On Error GoTo 0
                Set FindNameLocal = Nothing
                For Each oName In oSheet.Names
                    strName = oName.Name
                    If Len(strLocalName) = Len(strName) Or Len(strLocalNameNoQuote) = Len(strName) Then
                        If strName = strLocalName Or strName = strLocalNameNoQuote Then
                            Set FindNameLocal = oName
                            GoTo GoExit
                        End If
                    End If
                Next
            End If
        End If
GoExit:
    End Function
函数FindNameLocal(oSheet作为工作表,sName作为字符串)作为名称
以名字命名
作为字符串的Dim strLocalName
暗色丝光沸石
将strName设置为字符串
设置FindNameLocal=Nothing
如果Len(sName)>0而非oSheet为Nothing且oSheet.Names.Count>0,则
出错时继续下一步
strLocalName=“”&oSheet.Name&“!”&sName
strlocalnameoquete=oSheet.Name&“!”和sName
Set FindNameLocal=oSheet.Names(strLocalName)
如果错误为0或(FindNameLocal.NameLocal strLocalName和FindNameLocal.NameLocal strlocalNameNoquete),则
错误转到0
设置FindNameLocal=Nothing
为oSheet中的每个oName。名称
strName=oName.Name
如果Len(strLocalName)=Len(strName)或Len(strLocalName)=Len(strName),则
如果strName=strLocalName或strName=strLocalName,则
设置FindNameLocal=oName
GoTo GoExit
如果结束
如果结束
下一个
如果结束
如果结束
戈西特:
端函数

我不完全清楚您是如何使用该范围的。如果试图将范围对象设置为名称字符串,则
set rng1=range(“myName”)
将从本地工作表名称返回范围(如果sheet1处于活动状态),否则将从工作簿名称返回范围。我认为这是最干净的解决方法-即在将活动工作表作为工作簿范围使用之前,测试活动工作表与承载本地名称的工作表是否不同。有意义吗?:)您还可以将parent.name与工作簿名称进行比较,但仍需要循环遍历这些名称以提取该集合。re:@brettdj的注释。根据您试图实现的目标,最简单的方法可能是在宏的开头添加一个临时工作表,在代码的结尾删除。不,无论您在哪一个工作表上。它首先返回工作表级别(如果存在多个工作表范围的工作表,则根据工作表顺序进行排序)。如果不存在工作表范围的,则返回wb范围的。我也不想设定范围。我只想得到COM对象,这样我就可以对它做任何需要做的事情。@Shark,你能对工作簿中的所有名称进行一次性分析,然后将工作簿范围内的命名范围保存到字典中吗?这种类型的缓存似乎可以缓解任何性能问题。我不确定这是否回答了我的问题。也许我误读了,但我需要得到这个名字的全球版本。这将返回工作表级别1,通过以wb.Names.Item(“Sheet1!myName”)的格式传递它,我已经可以这样做了。我确实注意到你的代码中有一件事我很好奇。在比较字符串之前比较长度是否会在很大程度上提高性能?我们通过传递全局名称和活动工作表名称来检测是否存在重复的全局本地名称。如果存在重复工作表,则需要更改工作表并重试,直到找到不包含重复工作表的工作表(或临时添加新工作表),以便在访问名称时获得全局工作表。在VBA中获取字符串的长度非常快,但比较字符串的速度很慢:不知道这在C#中的应用程度。啊,现在有意义了。我得看看你的方法(翻译成C)是否比我想出的另一个想法快。我将发布解决方案作为另一个答案。然后性能测试将决定胜利者!顺便说一句,如果你用美国英语工作,你应该能够跳过For Each循环。