提问人:RobBaker 提问时间:11/7/2023 更新时间:11/7/2023 访问量:16
有没有办法在使用 ExcelDNA 生成的 XLL 中对同一 UDF 的调用之间缓存数据?
Is there a way to cache data between calls to the same UDF in an XLL generated using ExcelDNA?
问:
我正在构建一个 Excel XLL 加载项(使用 ExcelDNA)来管理对 Excel 计算集合的数据导入,并且对 UDF 的调用结构感到困惑。我想要实现的(以及该工具的旧 VBA 版本确实实现)是:
- C# 中的 UDF,可以从 Excel 单元格调用(这正在工作)。
- 所述UDF需要检查某些缓存数据(在C# XLL内存空间中)是否可用(这让我感到困惑)。
- 如果缓存的数据可用,则 UDF 需要检索此数据,否则需要执行其他操作(获取数据并缓存数据)。(这是行不通的,但我认为一旦我破解了 2 号,这将是不言而喻的)
我的 UDF 代码(大量简化为兴趣点)是:
using ExcelDna.Integration;
using System.Collections.Generic;
public static class MyFunctions
{
[ExcelFunction(Description = "Get Data function")]
public static string GetEBData(string name)
{
string filename = <some code to get the caller FullName - TBC>;
Dictionary<string, Data_Tool.DataCache> calcs;
if (!calcs.ContainsKey(filename)) calcs.Add(filename, new Data_Tool.DataCache(filename));
//<some code to get the result from the Dictionary or elsehwere>
return result;
}
}
我不认为 Dictionary 定义的位置是正确的,因为它应该以某种方式存在于特定的 UDF 调用之外(UDF 调用应该能够“看到”该 Dictionary 并检查其中的项目 - 本质上它是一个以每个 Excel 工作簿文件路径为键的字典)。但是我应该把字典的定义和分配放在哪里呢? 我目前也收到一个错误,因为我在检查 null 时使用了未分配的“calcs”。
显然,我的类 Data_Tool.DataCache 将文件名作为构造函数参数,我想为每个打开并使用 XLL UDF 的工作簿构建这些对象实例的字典。
我基本上缺少的是,如果这有意义,哪些代码在比 UDF 定义本身“更高级别”运行? 我还想知道作为一个额外的问题,是否有人知道如何从使用 ExcelDNA 调用 UDF 的单元格中获取 Workbook.FullName 属性?我无法通过我的工作电脑进入 Google 网上论坛,因此无法查看那里。
答:
0赞
RobBaker
11/7/2023
#1
我猜到了答案。似乎我可以像这样在 UDF 之外声明一个静态字典:
using ExcelDna.Integration;
using System.Collections.Generic;
public static class MyFunctions
{
static Dictionary<string, Data_Tool.DataCache> calcs = new Dictionary<string, Data_Tool.DataCache> { };
[ExcelFunction(Description = "Get Data function")]
public static string GetEBData(string name)
{
string filename = <some code to get the caller FullName - TBC>;
if (!calcs.ContainsKey(filename)) calcs.Add(filename, new Data_Tool.DataCache(filename));
//<some code to get the result from the Dictionary or elsehwere>
return result;
}
}
我现在只需要确保在文件关闭或缓存过期时从字典中删除对象;但从本质上讲,我认为有一条前进的道路。
还研究了如何使用帮助程序函数获取调用方文件路径:
private static string CallerName()
{
ExcelReference caller = (ExcelReference)XlCall.Excel(XlCall.xlfCaller);
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm, caller);
return System.IO.Path.Combine((string)XlCall.Excel(XlCall.xlfGetDocument, 2, sheetName), (string)XlCall.Excel(XlCall.xlfGetDocument, 88, sheetName));
}
评论