EPPlus 将范围乘以返回 ValueError 的 VLookup 函数中的常量



我在 ASP.Net 应用程序中使用了EPPlus库。 我正在尝试做的是打开一个电子表格,将一些值输入到单元格中,然后读取另一个包含计算结果的单元格。电子表格本身是保密的,所以我无法提供很多细节。

为了使我的计算正常工作,我不得不修改EPplus的源代码,更改ExcelAddressExpression.cs文件中的Compile函数以忽略ParentIsLookupFunction布尔值,如问题底部所示。

所以它能够评估术语 5*$f$7

我想知道的是,在什么情况下将 CompileResult 保留为 ExcelAddress 很有用,这样我就不会在电子表格的其他部分遇到任何不正确的计算或错误。

作为参考,以下是我到达此处的步骤:

我的代码是这样的

using (ExcelPackage p = new ExcelPackage(FilePath, true))
{
ExcelWorksheet ws = p.Workbook.Worksheets["Calculations"];
ws.Cells["b7"].Value = 50;
ws.Cells["f9"].Value = 500000;
ws.Cells["j216"].Calculate();
string result = ws.Cells["j216"].Value.ToString();
}

单元格 J216 中的公式为

=VLOOKUP($B$7+$F$221+$K$13-$F$8-1,Sheet2!$A$4:$T$103,5*$F$7+2*$B$8+$B$9-5,FALSE)

我得到的结果是"#VALUE!

我附加了一个日志文件,发现问题出在 VLookup 函数中

Worksheet: Calculations
Address: J216
OfficeOpenXml.FormulaParsing.Exceptions.ExcelErrorValueException: #VALUE!
at OfficeOpenXml.FormulaParsing.Excel.Functions.IntArgumentParser.Parse(Object obj)
at OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup.LookupArguments..ctor(IEnumerable`1 arguments, ArgumentParsers argumentParsers, ParsingContext context)
at OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup.VLookup.Execute(IEnumerable`1 arguments, ParsingContext context)
at OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers.LookupFunctionCompiler.Compile(IEnumerable`1 children, ParsingContext context)
at OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionExpression.Compile()

我采取的下一步是下载 EPPlus 的源代码,并在执行代码时对其进行调试,最终发现问题出在 Operator 的第 165 行.cs

l = l ?? new CompileResult(0, DataType.Integer);
r = r ?? new CompileResult(0, DataType.Integer);
if (l.DataType == DataType.Integer && r.DataType == DataType.Integer)
{
return new CompileResult(l.ResultNumeric*r.ResultNumeric, DataType.Integer);
}
else if ((l.IsNumeric || l.IsNumericString || l.IsDateString || l.Result is ExcelDataProvider.IRangeInfo) &&
(r.IsNumeric || r.IsNumericString || r.IsDateString || r.Result is ExcelDataProvider.IRangeInfo))
{
return new CompileResult(l.ResultNumeric*r.ResultNumeric, DataType.Decimal);
}
return new CompileResult(eErrorType.Value); 

在计算等式 5*$F$7 时,第二个参数是数据类型 ExcelAddress,这会导致引发编译结果异常。

造成这种情况的根本原因是在ExcelAddressExpression的编译函数中.cs文件中,ParentIsLookupFunction布尔值控制单元格是计算还是保留为地址。

public override CompileResult Compile()
{
if (ParentIsLookupFunction)
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}

我已经修改了我的代码版本,简单地

public override CompileResult Compile()
{
return CompileRangeValues();
}

正如问题顶部所说,我想知道的是为什么要返回 ExcelAddress 编译结果,它显然是有原因的,我不想破坏电子表格中的其他一些计算。

我可以确认,至少对于此计算,它现在可以正常工作。

几年前我写了EPPlus的公式引擎,但现在在这个项目上工作不多。如果我没记错的话,在某些情况下,您不想在表达式中编译 excel 地址,而是将其传递给执行函数。您是否尝试过运行单元测试?公式引擎由数百个测试覆盖,测试结果可以提供一些指导。

在尝试了不同的电子表格后,我能够回答这个问题。

在地址未像我之前的示例5*$F$7那样操作地址的情况下,将值作为 ExcelAddress 返回很有用,例如 VLookup 中的 IF 语句。

如果有运算符,您将需要返回单元格的内容。 我修改了 EPPlus 代码,现在检查是否有任何运算符在公式中分隔项

public override CompileResult Compile()
{
if (ParentIsLookupFunction &&
Operator == null && 
(Prev == null || Prev.Operator == null))
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}

最新更新