【问题标题】:Is it Possible to Assign an Alias to a Function?是否可以为函数分配别名?
【发布时间】:2018-01-21 10:52:09
【问题描述】:

我在写一个简单的函数,比如:

Function myFunction() As Variant
    'Some rules
End Function

对于上述函数,是否可以像使用 API 调用那样分配 别名

显然这不是正确的语法,但你明白了:

Function myFunction() Alias myFunc As Variant
    'Some rules
End Function

这将允许我使用任一名称:

Sub Test()
    Debug.Print myFunction
    Debug.Print myFunc
End Sub

【问题讨论】:

  • 我相信之前有人问过这个问题here
  • @TheNotSoGuru,我添加了一个基于所谓 SoundEx 搜索 的全新答案,因为您稍微修改了 初始问题(参见 1/ 22) 并且为了让人们清楚地了解获取函数名称的独立且可能是创新的方法。

标签: vba excel function alias


【解决方案1】:

我不明白为什么你需要一个 VBA 函数的 VBA 别名。

API 别名用于引用 DLL 中的函数或其他对象, 如果它是“给定的名称”,则不能在需要它的模块中使用。

Alias —— 表示被调用的过程有另一个 DLL 中的名称。当外部过程名称为 与关键字相同。当 DLL 过程有 与公共变量、常量或任何其他过程同名 相同的范围。如果 DLL 中有任何字符,别名也很有用 DLL 命名约定不允许使用过程名称。 (Source)

...但要回答您的问题,当然您可以为函数创建备用名称,只需对您的代码稍作修改:


你的职能:

Function myFunction() As Variant
    'Some rules
End Function

指定一个备用名称:

Function myFunc() As Variant
   myFunc = myFunction
End Function

这将允许您使用任一名称:

Sub Test()
    Debug.Print myFunction
    Debug.Print myFunc
End Sub

编辑:“不记得 UDF 名称”

(当我说我不明白你为什么需要这样做时,我以为你没有像我这样的记忆力!现在我理解你的推理,给出了多个名字到相同的函数!)

什么,除了 1000 个内置函数、过程和对象之外,您还没有记住所有自定义 VBA 函数的名称和语法,以及看似 属性、方法和类名的无限列表??

我也没有。

在使用 VBA 编码时有助于触发我记忆的功能是 属性/方法列表

开始输入函数的名称或过程并点击Ctrl+J您将获得一份自定义内置函数、方法、过程等列表**

我注意到您的示例函数名称都以“my”开头。这可能只是为了说明的目的,但是,通过在“属性/方法”对话框中将您的函数分组在一起,这样的特定命名约定也将有所帮助。


更多记住工作原理它们叫什么的方法:

您还可以向 UDF(用户定义函数)添加描述,在工作表上输入函数名称时会出现该描述:

请参阅:How to put a 'Tooltip' on a user-defined function


相关:


比描述更进一步,注册用户定义的函数不仅可以创建函数的描述,还可以创建每个函数的详细信息函数的参数及其数据类型;您甚至可以指定快捷键,添加指向自定义“帮助”文件/页面的链接,以及甚至为 UDF 分配一个类别

这些扩展属性显示在 Insert Function 对话框中,可通过单击编辑栏左侧的 按钮或按 Shift+F3:

Excel 没有用于编辑参数描述的内置界面,因此需要 VBA。相关文档可能很难找到。


关于注册用户定义函数的代码和信息 -:


创建功能区按钮以列出 VBA 过程

我还没有尝试过,但我可以看到它非常方便,特别是因为它很容易进一步定制,也许可以使用项目特定的功能列表和其他信息。

可以将按钮添加到功能区,单击该按钮时会显示 VBA 过程/函数列表,使用 XML 和 VBA 从按钮显示用户表单。还有一个选项可以将程序列表保存到文本文件中。

您已经可以通过“开发人员”选项卡上的“宏”按钮查看工作簿中的过程。但是,只有模块和工作表中的无参数子例程才会显示在“宏”对话框中。不显示带参数的函数和子例程。本专栏中描述的代码显示了工作簿中的所有子例程和函数。

更多信息和完整代码可用here


编写 VBA 代码的 VBA 代码!?

通过以编程方式操作 VBA 编辑器 (VBE),您可以在 VBA 中编写代码来读取或修改其他 VBA 项目、模块和过程,并可用于自动执行与开发相关的任务。这被称为 extensibility 因为它扩展了 编辑器 -- 您可以使用 VBA 代码来创建新的 VBA 代码。您可以使用这些功能编写创建、更改或删除 VBA 模块和代码过程的自定义过程。

了不起的Chip Pearson 再次做到了这一点,此处提供了详细说明和完整代码,以了解可扩展性可以为您做的一些有趣的事情。

Chip 页面上的部分代码列表(here):

  • 在项目中添加/删除/重命名模块
  • 在模块中添加/删除/重命名过程
  • 在项目之间复制模块
  • 在代码模块中创建新过程
  • 创建事件过程
  • 列出模块中的所有过程
  • 阅读过程声明
  • 在模块中搜索文本
  • 修复 VBE 中的屏幕闪烁问题
  • 将 VBComponent 导出到文本文件
  • 测试 VBComponent 是否存在
  • 确定与 VBProject 关联的工作簿
  • 计算模块/项目/组件中的代码行数

这些方法使用 VBA 可扩展性 [库] (http://www.exceltoolset.com/setting-a-reference-to-the-vba-extensibility-library-by-code/)(参考),并且需要以编程方式访问 VBA 项目,这是 Excel 的安全设置选项。有关详细信息,请参阅 Chip 的页面。

Chip 的页面在 Customizing Menus with VBA 上也有大量信息和代码,这可能有助于让开发人员自己的工作更轻松。


如果功能可以控制甚至拦截内置命令,VBA 的一个看似“被遗忘”的能力。这也可以用来使开发人员受益(尤其是记忆力差的开发人员!)...来自 Microsoft here 的更多信息和示例。


【讨论】:

  • 我现在明白了 - 内存 问题 - 这更有意义。当我说我不明白你为什么需要这样做时,我以为你没有像我这样的记忆力!这一点我完全可以理解。一般来说,我的解决方案是在我的工作区放置白板。 :-)
  • @TheNotSoGuru 为什么不使用一致的命名约定?这种基于别名的方法迟早会成为调试难题。
  • @TheNotSoGuru 正如 John Coleman 所说,解决内存问题的方法就是保持一致的命名约定。所有函数都应该有描述性的名称,并且应该是动词(例如verify、get、pull等)。我发现“Get”对于返回某些内容的函数最有用。我还强烈推荐不使用缩写的名称(因此,VerifyRange 优于 VerifyRng),但这是个人喜好。一致的名称比别名更重要。
  • 另一个有用的记忆帮助是将相关函数放在不同的模块中并重命名您的模块 - 我几乎总是有一个名为 G 的模块用于全局变量,一个名为 DB 用于数据库连接和函数,一个 Util 用于实用功能。然后键入模块名称,后跟点,该模块中的所有公共函数都会自动列出,就像类模块一样。
  • @QHarr — 不是很方便吗?!ScreenToGif。如果“一张图片说 1000 个单词”,那么在试图解释技术性的东西时,动画 GIF 会说多少个单词? ...另外,我一直在寻找它在此之外的新用途;以至于我觉得有义务向开发者捐款……
【解决方案2】:

简单的 VBA 示例(无类)

当您称自己为 TheNotSoGuru 时,请尝试以下相对简单的方法:您必须在 ONE 中编写别名定义,而不是像 alias 定义这样的 API用户定义的 alias() 函数

调用测试程序

这将向您展示如何使用 ONE 用户定义的alias 函数调用您的别名;第一个参数是您的别名字符串,其他参数定义原始函数本身的可能参数:

Option Explicit     ' declaration head of your code module

Sub Test()
Debug.Print "0) Original Function", myFunction
Debug.Print "1) alias(""(myFunc1"")", alias("myFunc1")
Debug.Print "2) alias(""(myFunc2"")", alias("myFunc2")      ' too less arguments
Debug.Print "2) alias(""(myFunc2"",false)", alias("myFunc2", False)
End Sub

示例函数

第一个例子需要没有参数第二个示例演示了一个不正确的别名函数调用以及一个正确的别名函数调用 - 原始函数处理一个布尔参数(TrueFalse)的输入。

Function myFunction() As Variant
'Some rules
'...
'return result
 myFunction = "Result from myFunction"
End Function

Function myFunctionWithOneArgument(Optional ByVal b As Boolean = True) As String
'Some rules
If b Then
   myFunctionWithOneArgument = "result from myFunctionWithOneArgument " & "okay"
Else
   myFunctionWithOneArgument = "result from myFunctionWithOneArgument " & "without comment"
End If
End Function

=============== Alias() 函数示例

您有责任将您的别名定义插入到别名函数中。 它甚至允许您通过错误处理引发 450 错误“参数数量错误...”来强制输入正确数量的参数。如果发生错误,消息框会显示错误消息。

Function alias(ByVal sFunc, Optional arg1, Optional arg2, Optional arg3)
On Error GoTo oops           ' error handler
Select Case sFunc & ""       ' check your own aliases as string values 
  Case "myFunc1", "1"        ' your alias Definition(s)
       alias = myFunction    ' return original function myFunction
  Case "myFunc2", "One"      ' see above
       ' defines if one argument is needed here:
       If IsMissing(arg1) Then Err.Raise (450)   ' too less arguments if arg1 is missing
       alias = myFunctionWithOneArgument(arg1)
  Case Else
       alias = "Unknown function alias " & sFunc
End Select
EverythingOkay:     Exit Function

oops:
MsgBox "Function: " & sFunc & vbNewLine & vbNewLine & _
       "Error No: " & Err.Number & vbNewLine & _
       Err.Description, vbExclamation, "Error - Wrong number of arguments"
Err.Clear
End Function

【讨论】:

  • 感谢您的回复。问题不在于我一定要故意调用别名,而是忘记了我许多人命名函数的开头(即verifyRangeverifyRng)。如果我知道我在调用别名开头,那么我就不需要调用别名。但是您的解决方案确实有效,而且经过深思熟虑。 +1
【解决方案3】:

通过相似度搜索别名

A) 简介

您在 1 月 22 日的评论:“问题不是我一定要故意调用别名,而是忘记我可能已经命名的函数开头的问题 (即。verifyRange vs verifyRng)。如果我知道我在调用别名开头,那么我不需要调用别名。但是你的解决方案确实有效,而且经过深思熟虑。”

由于您在上面引用的评论中的示例:当您稍微修改了最初的问题时,我想到了一个替代解决方案并将其添加为独立的新答案

► 您可以利用所谓的 SoundEx 搜索,根据语音算法程序名称进行分组。

方法:Soundex 代码 标识一组发音相似的术语、名称或... ► 程序名称。如果您将其与通过所有现有过程/函数的 VBIDE 列表的循环结合起来(不要忘记设置参考),您可以获得最可能的别名(es)列出。

示例结果

1/1 Project(s): "VBAProject" (D:\Excel\test.xlsm)
**Project name: "VBAProject" ** (Host Project)
++SoundEx("verifyRange")="V616"
--   Found --  Procedure/Function name(s) ---------  ------------------
[Prc: Sub]     verifyRng   in Std Module modTest1    Line#: 2/[Body: 3]
[Prc: Sub]     verifyRange in Std Module modSortDict Line#: 6/[Body: 6]

注意:此方法基于人类语音(双唇音、唇齿音)的六种语音分类构建压缩字母数字代码 、牙齿、牙槽、软颚和声门),去除人声和一些出现的“H”、“W”和“Y”;该代码由第一个大写字母和后面的三个数字组成(如果找不到更多辅音,则填充 0)。 BTW 起源可以追溯到 1800 年代后期,用于索引美国人口普查记录

链接

Find the word which I closest to the particular string? http://www.creativyst.com/Doc/Articles/SoundEx1/SoundEx1.htm#JavaScriptCode https://en.wikipedia.org/wiki/Soundex

Soundex 示例

要演示 soundex 编码,请尝试以下示例调用,结果相同:

Sub testSoundEx()
Dim i As Integer
Dim a()
a = Array("verifyRange", "verifyRng", "vrfRanges")
Debug.Print "Proc name", "SoundEx Code": Debug.Print String(50, "-")
For i = LBound(a) To UBound(a)
    Debug.Print a(i), SoundEx(a(i))
Next i
End Sub

SoundEx 函数

Function SoundEx(ByVal s As String) As String
' Site:   https://stackoverflow.com/questions/19237795/find-the-word-which-i-closest-to-the-particular-string/19239560#19239560
' Source: Developed by Richard J. Yanco
' Method: follows the Soundex rules given at http://home.utah-inter.net/kinsearch/Soundex.html
Dim Result As String, c As String * 1
Dim Location As Integer
s = UCase(s)                ' use upper case
' First character must be a letter
If Len(Trim(s)) = 0 Then
   Exit Function
ElseIf Asc(Left(s, 1)) < 65 Or Asc(Left(s, 1)) > 90 Then
    SoundEx = ""
    Exit Function
Else
  ' (1) Convert to Soundex: letters to their appropriate digit,
    '             A,E,I,O,U,Y ("slash letters") to slashes
    '             H,W, and everything else to zero-length string
    Result = Left(s, 1)
    For Location = 2 To Len(s)
        Result = Result & Category(Mid(s, Location, 1))
    Next Location
  ' (2) Remove double letters
    Location = 2
    Do While Location < Len(Result)
        If Mid(Result, Location, 1) = Mid(Result, Location + 1, 1) Then
            Result = Left(Result, Location) & Mid(Result, Location + 2)
        Else
            Location = Location + 1
        End If
    Loop
   ' (3) If category of 1st letter equals 2nd character, remove 2nd character
    If Category(Left(Result, 1)) = Mid(Result, 2, 1) Then
        Result = Left(Result, 1) & Mid(Result, 3)
    End If
   ' (4) Remove slashes
    For Location = 2 To Len(Result)
        If Mid(Result, Location, 1) = "/" Then
            Result = Left(Result, Location - 1) & Mid(Result, Location + 1)
        End If
    Next
   ' (5) Trim or pad with zeroes as necessary
    Select Case Len(Result)
        Case 4
            SoundEx = Result
        Case Is < 4
            SoundEx = Result & String(4 - Len(Result), "0")
        Case Is > 4
            SoundEx = Left(Result, 4)
    End Select
End If
End Function

SoundEx() 调用的辅助函数

这个辅助函数根据语音分类返回一个字母代码(见上面的注释):

Private Function Category(c) As String
'   Returns a Soundex code for a letter
Select Case True
    Case c Like "[AEIOUY]"
        Category = "/"
    Case c Like "[BPFV]"
        Category = "1"
    Case c Like "[CSKGJQXZ]"
        Category = "2"
    Case c Like "[DT]"
        Category = "3"
    Case c = "L"
        Category = "4"
    Case c Like "[MN]"
        Category = "5"
    Case c = "R"
        Category = "6"
    Case Else 'This includes H and W, spaces, punctuation, etc.
        Category = ""
End Select
End Function

► 解决您的问题 - 通过别名获取函数的示例调用

B) 记忆问题或如何锻炼记忆

您可以使用以下示例调用通过语法listProc {function name string} 搜索过程/函数别名,例如listProc "verifyRange" 并且您会在 Visual Basic 编辑器 (VBE) 的 即时窗口 中获得一个精简的所有找到的别名列表

Sub Test()
listProc "verifyRange"  ' possibly gets verifyRange AND verifyRng via SoundEx "V616"
'listProc "verify"      ' possibly gets nothing, as SoundEx "V610" has no fourth consonant
'listProc                '[ displays ALL procedures without SoundEx Filter ]
End Sub

注意:请记住,SoundEx 代码(例如,verifyRange 的“V616”)的长度限制为四个字母数字字符。 如果您只寻找“verify”(= 3 个辅音 V+r+f),您会得到“V610”而不是“verifyRange”或“verifyRng”(V+r+f+r)。 在这种情况下,您应该搜索一对变体。

============================== 主程序listProc =====================

Sub listProc(Optional ByVal sFuncName As String)
' Purpose: display procedures using a SoundEx Filter
' Call:   0 arguments or empty argument - ALL procedures without filter
'         1 argument (not empty)        - procedures found via SoundEx
' Note:   requires reference to Microsoft Visual Basic for Applications Extensibility 5.3
' Declare variables to access the macros in the workbook.
Dim VBAEditor      As VBIDE.VBE         ' VBE
Dim objProject     As VBIDE.VBProject   ' Projekt
Dim objComponent   As VBIDE.VBComponent ' Modul
Dim objCode        As VBIDE.CodeModule  ' Codeblock des Moduls
' Declare other miscellaneous variables.
Dim sProcName      As String
Dim sndx As String, sndx2 As String
Dim pk             As vbext_ProcKind       ' proc kind (Sub, Function, Get, Let)
Dim strPK          As String, sTyp As String
Dim iLine          As Integer, iBodyLine As Integer, iStartLine As Integer
Dim i              As Integer
Dim bShow          As Boolean             ' show procedure name
Dim bSoundEx       As Boolean
If Len(Trim(sFuncName)) > 0 Then bSoundEx = True  ' show alle procedures!
' ========================================
' Get the project details in the workbook.
' ========================================
  Set VBAEditor = Application.VBE

  Set objProject = VBAEditor.ActiveVBProject
' Set objProject = VBAEditor.VBProjects("MyProcject")   ' 1-based, project name or item number

 For i = 1 To VBAEditor.VBProjects.Count    ' show name, filename, buildfilename (DLL)
     Debug.Print i & "/" & _
                 VBAEditor.VBProjects.Count & " Project(s): """ & _
                 VBAEditor.VBProjects(i).Name & """ (" & VBAEditor.VBProjects(i).filename & ")"
 Next i
' get SoundEx of Function name
  sndx2 = SoundEx(sFuncName)
' ==================
' ? PROJECT NAME
' ==================
'   objProject.Type ...vbext_pt_HostProject 100 Host-Project
'                   ...vbext_pt_StandAlone  101 Standalone-Project
  Debug.Print "**Project name: """ & objProject.Name & """ ** (" & _
              IIf(objProject.Type = 100, "Host Project", "Standalone") & ")"
  If bSoundEx Then Debug.Print "++SoundEx(""" & sFuncName & """)=""" & sndx2 & """" & _
                               vbNewLine & "--   Found --  Procedure/Function name(s)"

' Iterate through each component (= Module) in the project.
For Each objComponent In objProject.VBComponents        ' alle MODULE
    ' Find the code module for the project (Codeblock in current component/=module).
      Set objCode = objComponent.CodeModule
      ' =============
      ' ? MODULE NAME
      ' =============
      If objCode.CountOfLines > 0 And Not bSoundEx Then
         Debug.Print " *** " & _
             sModType(objComponent.Type) & " ** " & objComponent.Name & " ** "
      End If
  ' Scan through the code module, looking for procedures.
  ' Durch alle Codezeilen des jeweiligen Moduls gehen
    iLine = 1
    Do While iLine < objCode.CountOfLines               ' alle Zeilen durchackern (1/End ...)

      ' =================
      ' Get Procedurename                               ' !! SETZT AUTOMATISCH >> pk << !!
      ' =================
        sProcName = objCode.ProcOfLine(iLine, pk)       ' jede nächste Zeile auf Prozedurbeginn checken

        If sProcName <> "" Then                         ' ohne Declaration head
            ' -----------------
            ' Found a procedure
            ' -----------------
            ' a) Get its details, and ...
              strPK = pk                                 ' 0-Prc|1-Let/2-Set/3-Get Werte abfangen !!!
           '' iStartLine = objCode.ProcStartLine(sProcName, strPK)  ' here = iLine !!
              iBodyLine = objCode.ProcBodyLine(sProcName, strPK)    ' Zeilennr mit Sub/Function/L/S/Get
              sTyp = sPrcType(objCode.Lines(iBodyLine, 1))          ' Sub|Fct|Prp
            ' b) Check Soundex
              If bSoundEx Then
                 sndx = SoundEx(sProcName)
                 If sndx = sndx2 Or UCase(sProcName) = UCase(sFuncName) Then
                    bShow = True
                 Else
                    bShow = False
                 End If
              Else
                 bShow = True
              End If
              ' ==============
              ' c) ? PROC NAME
              ' --------------
              If bShow Then
                 Debug.Print "    " & "[" & sPK(strPK) & ": " & sTyp & "] " & _
                          sProcName & IIf(bSoundEx, " in " & sModType(objComponent.Type) & " " & objComponent.Name, "") & vbTab, _
                          "Line#: " & iLine & "/[Body: " & iBodyLine & "]"
              End If
            ' -------------------------------------------
            ' d) Skip to the end of the procedure !
            '    => Add line count to current line number
            ' -------------------------------------------
              iLine = iLine + objCode.ProcCountLines(sProcName, pk)
        Else
            ' This line has no procedure, so => go to the next line.
            iLine = iLine + 1
        End If
    Loop

Next objComponent

' Clean up and exit.
  Set objCode = Nothing
  Set objComponent = Nothing
  Set objProject = Nothing


End Sub

主过程listProc的3个辅助函数

这些辅助函数返回附加信息给过程和模块:

Function sPK(ByVal prockind As Long) As String
' Purpose: returns short description of procedure kind (cf ProcOfLine arguments)
Dim a(): a = Array("Prc", "Let", "Set", "Get")
sPK = a(prockind)
End Function

Function sPrcType(ByVal sLine As String) As String
' Purpose: returns procedure type abbreviation
If InStr(sLine, "Sub ") > 0 Then
   sPrcType = "Sub"     ' sub
ElseIf InStr(sLine, "Function ") > 0 Then
   sPrcType = "Fct"     ' function
Else
    sPrcType = "Prp"    ' property (Let/Set/Get)
End If
End Function

Function sModType(ByVal moduletype As Integer) As String
' Purpose: returns abbreviated module type description
Select Case moduletype
   Case 100
     sModType = "Tab Module"
   Case 1
     sModType = "Std Module"
   Case 2
     sModType = "CLS Module"
   Case 3
     sModType = "Frm Module"
   Case Else
     sModType = "?"
 End Select
End Function

【讨论】:

    猜你喜欢
    • 2010-09-16
    • 2016-10-25
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    相关资源
    最近更新 更多