在 VBA 中编写 UDF 以暴露给 Excel 单元格是直截了当的,只需在 VBA 模块中编写函数,Bob 就是你的叔叔。但是,使用托管语言(例如 C# 或 F#)将函数公开给 Excel 会稍微复杂一些。

从本质上讲,有两种方法可以实现这一点,每种方法都有优点和缺点:

  1. 自动化插件方法
  2. XLL 加载项方法

我将演示如何实现每种方法,然后我将讨论我的判断。我在每种方法中都创建了一个示例项目;你可以在这篇文章的末尾下载它。

自动化插件方法

自动化插件是从 Excel 工作表中的公式调用的 COM 函数,自 Excel 2002 起就支持它。这个想法是 .NET 可以公开一个 COM 接口,该接口可以通过自动化插件支持从 Excel 中使用。

要创建自定义函数,您需要从 Visual Studio 创建一个新的 C# 代码库项目,然后转到:
右键单击项目 > 属性 > 构建 > 注册 COM 互操作并启用它。

然后转到Assembly.cs并设置ComVisibletrue. 然后,您需要创建一个稍后将继承的基类来创建您的 UDF:

C#
收缩▲   
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;namespace ExcelUdf.Automation
{
public abstract class UdfBase
{
[ComRegisterFunction]
public static void ComRegisterFunction(Type type)
{Registry.ClassesRoot.CreateSubKey(GetClsIdSubKeyName(type, "Programmable"));// Solves an intermittent issue where Excel// reports that it cannot find mscoree.dll// Register the full path to mscoree.dll.var key = Registry.ClassesRoot.OpenSubKey(GetClsIdSubKeyName(type, "InprocServer32"), true);if (key == null){return;}key.SetValue("", String.Format("{0}\\mscoree.dll", Environment.SystemDirectory), RegistryValueKind.String);
}[ComUnregisterFunction]
public static void ComUnregisterFunction(Type type)
{// Adds the "Programmable" registry key under CLSIDRegistry.ClassesRoot.DeleteSubKey(GetClsIdSubKeyName(type, "Programmable"));
}private static string GetClsIdSubKeyName(Type type, String subKeyName)
{return string.Format("CLSID\\{{{0}}}\\{1}", type.GUID.ToString().ToUpper(), subKeyName);
}// Hiding these methods from Excel
[ComVisible(false)]
public override string ToString()
{return base.ToString();
}[ComVisible(false)]
public override bool Equals(object obj)
{return base.Equals(obj);
}[ComVisible(false)]
public override int GetHashCode()
{return base.GetHashCode();
}
}
}

那么你的 UDF 类应该继承UdfBase如下:

C#
using System.Runtime.InteropServices;
using ExcelUdf.Automation;namespace AutomationSample
{[ClassInterface(ClassInterfaceType.AutoDual)][Guid("7a9de936-0e99-4d37-9c2b-a02a09fb371f")]public class AutomationSample : UdfBase{public double AutomationSampleAdd(double a, double b){return a + b;}public double AutomationSampleSubtract(double a, double b){return a - b;}}
}

构建您的项目,最后一步是打开一个 Excel 文件,转到:文件 > 选项,然后选择加载项。在下拉列表中选择“Excel Add-Ins”,然后点击“Go...”。选择“自动化”按钮并选择您的组件(在本例中,要选择的项目名称是AutomationSample.AutomationSample)。

在工作表单元格中写入=AutomationSampleAdd(1,2),您应该得到3.

引用 Excel 的自动化加载项方法

上面提到的前一种方法允许 Excel 调用 .NET,而不是相反。如果您想引用执行 .NET 代码的 Excel 应用程序怎么办?假设根据某些标准或异步回调为某些工作表列着色。在这种情况下,您需要实现IDTExtensibility2接口。

要实现该方法,需要引用右侧显示的程序集,继承UdfBase abstract类并实现IDTExtensibility2接口。

C#
收缩▲   
using System;
using ExcelUdf.Automation;
using Extensibility;
using Microsoft.Office.Interop.Excel;namespace ExcelUdf.ExtensibilityAutomation
{
public abstract class UdfExtensibilityBase : UdfBase, IDTExtensibility2
{
protected Application ExcelApplication { get; set; }public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst,ref Array custom)
{ExcelApplication = application as Application;
}public void OnDisconnection(ext_DisconnectMode removeMode, ref Array custom)
{
}public void OnAddInsUpdate(ref Array custom)
{
}public void OnStartupComplete(ref Array custom)
{
}public void OnBeginShutdown(ref Array custom)
{
}
}
}

在我的下载项目中,我在一个独立的项目中实现了这个类,而不是将它与现有的一个结合起来。原因是这种方法需要引用特定的 Excel 互操作组件版本。一旦你有了这些引用,你的部署项目的复杂性就会增加,因为现在你需要管理更多的依赖项并确保在目标机器上安装了正确的引用版本的 Excel(如果你想避免这种情况,请检查NetOffice )。

要创建 UDF 方法并引用当前 Excel 实例:

C#
收缩▲   
using System.Runtime.InteropServices;
using ExcelUdf.ExtensibilityAutomation;namespace ExtensibilitySample
{
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("7a9de936-0e99-4d38-9c2b-a02a09fb371f")]
public class ExtensibilitySample : UdfExtensibilityBase
{public double ExtensibilitySampleAdd(double a, double b){return a + b;}public string WhoAreYou(){string name = ExcelApplication.Application.InputBox("Who are you?");if (string.IsNullOrWhiteSpace(name)){return string.Empty;}return "Hello " + name;}
}
}

如上所述,将此项目与 Excel 一起使用。

XLL 加载项方法

XLL 是 Excel 的加载项,您可以使用任何支持构建本机 DLL(动态链接库)的编译器构建它,它从 Excel 97 开始受支持。它比自动化加载项更快并且具有更多功能,但 XLL组件通常通过 C/C++ 构建。

对 .NET 来说幸运的是,有一个开源组件具有一个名为Excel DNA的许可许可证,它允许 .NET 轻松构建 XLL 插件。

要构建 XLL 组件,请创建一个新项目,下载Excel DNA并引用ExcelDna.Integration.dll,然后编写您的函数:

C#
using ExcelDna.Integration;namespace XllSample
{public class XllSample{[ExcelFunction(Description = "Adds two numbers", Category = "XLL with .NET Sample Function")]public static double XllSampleAdd(double a, double b){return a + b;}}
}

构建,然后创建一个名为YourDllName.dna的文件,在本例中为 XllSample.dna,其内容如下:

XML
<DnaLibrary RuntimeVersion="v4.0"><ExternalLibrary Path="XllSample.dll" />
</DnaLibrary>

将其放在您的 DLL 旁边,然后将ExcelDna.xllExcelDna64.xll复制到您的 DLL 旁边,并将其重命名以匹配您的 DLL 名称,在本例中为 XllSample.xll

构建您的项目,最后一步是打开一个 Excel 文件,转到:文件 > 选项,然后选择加载项。在下拉列表中选择“Excel Add-Ins”,然后点击“Go...”。选择“浏览”按钮并选择您的XllSample.xll

在 Excel 单元格中,开始输入XllSampleAdd,然后您将通过 Excel 的自动完成功能获得其余功能。

比较

这是两种方法之间的比较表:

自动化插件 XLL 加载项
最低支持版本 Excel 2002 Excel 97
表现 慢点 快点
UDF 自动完成 不支持 支持的
UDF Documentation Tooltip Not supported Supported
Building in .NET Easier Harder (without a 3rd party component)

在 Excel 中使用 C# .NET 用户定义函数 (UDF)相关推荐

  1. 【解析】在高级语言源程序中, 常需要用户定义的标识符为程序中的对象命名,常见的命名对象有()

    在高级语言源程序中, 常需要用户定义的标识符为程序中的对象命名,常见的命名对象有() A.关键字 B.变量 C.函数 D.数据类型 E.注释 一个一个分析: 关键字 :虽然很多关键字都可以用过defi ...

  2. oracle 触发器 execute immediate,过程、触发器、用户定义函数和批处理中使用的 EXECUTE IMMEDIATE...

    过程.触发器.用户定义函数和批处理中使用的 EXECUTE IMMEDIATE EXECUTE IMMEDIATE 语句允许使用文字字符串(在引号中)和变量的组合来构建语句.例如,以下过程包含创建表的 ...

  3. db2 控制台执行创建函数语句_DB2中创建和使用SQL用户定义函数

    本文将为您详细介绍DB2数据库中创建用户自定义行数,用以扩展扩展内置的 DB2 函数的方法,供您参考,希望对您有所帮助. 可以创建用户定义函数来扩展内置的 DB2 函数.例如,创建计算复杂的算术表达式 ...

  4. 使用脚本编写 Vim 编辑器,第 2 部分: 用户定义函数

    用户定义函数 Haskell 或 Scheme 程序员会告诉您,函数对于任何严肃的编程语言来说都是最重要的特性.对于 C 或 Perl 程序员,他们也会告诉您完全相同的观点. 函数为严肃的程序员提供了 ...

  5. 数据库原理与应用(SQL Server)笔记 第十章 用户定义函数

    目录 前言 一.用户定义函数的定义 二.用户定义函数的分类 三.标量函数和内联表值函数 (一)标量函数的定义 (二)标量函数的调用 1.SELECT语句调用 2.EXEC语句调用 (三)内联表值函数的 ...

  6. SQL Prompt数据库教程:标量用户定义函数误用作常量

    SQL Prompt是一款实用的SQL语法提示工具.SQL Prompt根据数据库的对象名称.语法和代码片段自动进行检索,为用户提供合适的代码选择.自动脚本设置使代码简单易读–当开发者不大熟悉脚本时尤 ...

  7. SQL service基础(九)用户定义数据类型和用户定义函数的概念、创建及使用方法

    实验目标: 1.学习和掌握用户定义数据类型的概念.创建及使用方法. 2.学习和掌握用户定义函数的概念.创建及使用方法. 创建一个数据库,执行shiyan15.sql脚本 一.创建和使用用户定义的函数( ...

  8. python关键字define_在Python中,使用关键字define定义函数。

    在Python中,使用关键字define定义函数. 以下属于生药学有效性评价的是A:有效成分定量分析B:限量检查C:重金属检测D:基原鉴定 若有如下定义和语句:A:7B:12C:8D:9 图示电路中的 ...

  9. c语言用average函数计算平均成绩,在excel中-Excel中,求平均值用Average函数;它可分用快捷键求平均值...

    在 Excel 中,求平均值用Average函数:它可分用快捷键求平均值.自动求平均值和输入公式求平均值,其中用快捷键求平均值速度最快,并且三种方法都可以对行列.任意单元格.指定区域甚至整个表格求平均 ...

最新文章

  1. java负数右移_收入囊中篇---Java程序基础(二)
  2. ASP.NET 4 和 Visual Studio 2010 Web 开发概述
  3. 基于 FPGA 的以太网回环测试verilog实现UDP协议
  4. java实现顺序栈_Java实现顺序栈原理解析
  5. HP P2000 RAID-5两块盘离线的数据恢复报告
  6. ajax中怎么验证data,我应该在jQuery的ajax成功处理程序中验证响应数据吗?
  7. 一个程序员的感慨的《虚拟光驱》
  8. PThread 学习笔记
  9. linux环境systwm.img解包,[教程] system.img解包打包的方法,方便菜鸟们制作直刷ROM...
  10. Julia: Flux.jl尝试
  11. 使用 ABAP 代码制作手机能够扫描的二维码(QRCode)
  12. sci论文发表的重复率要求低于多少
  13. i春秋 - Exploit-Exercises: Nebula - level03
  14. Ubuntu20.04下安装nvidia驱动
  15. python重写和重载的区别_(C#)重载和重写的区别
  16. 什么是异地双活及应用场景
  17. 【深度学习】语义分割:论文阅读:(CVPR 2022) MPViT(CNN+Transformer):用于密集预测的多路径视觉Transformer
  18. 华为机试真题 C++ 实现【叠积木】
  19. JavaMail实现注册邮箱验证案例
  20. NFT Insider #65:韩国娱乐业巨头CJ ENM与The Sandbox达成合作,YGG 建立巴西社区的SubDAO

热门文章

  1. 计算机毕业设计JAVA酒店物联网平台系统mybatis+源码+调试部署+系统+数据库+lw
  2. 小米4 第三方re奇兔_【搞事】小米上架39元充电器 20W可适配iPhone 12系列
  3. Codeforces 444C DZY Loves Colors 线段树区间更新
  4. go语言快速学习指南
  5. 软件项目开发业界通常报价和收费方式
  6. Guido 转身离去,Python 何去何从?
  7. java编程、语言学习,入门必看(上)
  8. 昨天我开除了一名程序员,因为简历造假!
  9. 元宇宙:未来我们的每一个日常行为是否都能成为赚钱工具?
  10. 多媒体应用: 图形、音频、视频