我正在ASP.Net应用程序中使用EPPlus库。 我想做的是打开一个电子表格,将一些值输入到单元格中,然后读取另一个包含计算结果的单元格。电子表格本身是机密的,因此我无法提供许多详细信息。
为了使我的计算生效,我不得不修改EPplus的源代码,更改ExcelAddressExpression.cs文件中的Compile函数,以忽略ParentIsLookupFunction bool,如问题底部所示。
因此它能够评估术语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.cs的第165行
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时,第二个参数是DataType ExcelAddress,这将导致抛出编译结果异常。
此问题的根本原因在于ExcelAddressExpression.cs文件的Compile函数,ParentIsLookupFunction布尔值布尔值控制是对单元格求值还是作为地址保留。
public override CompileResult Compile()
{
if (ParentIsLookupFunction)
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}
我已将代码版本修改为
public override CompileResult Compile()
{
return CompileRangeValues();
}
就像在问题的顶部说的那样,我想知道的是为什么要返回ExcelAddress CompileResult,这显然是有原因的,我不想破坏电子表格中的其他一些计算。
我可以确认,至少对于这种计算,它现在可以正常工作。
答案 0 :(得分:0)
几年前,我编写了EPPlus的公式引擎,但如今在该项目上工作不多。如果我没记错的话,在某些情况下,您可能不想在表达式中编译excel地址,而是将其传递给执行函数。您是否尝试过运行单元测试?公式引擎包含数百个测试,测试结果可以提供一些指导。
答案 1 :(得分:0)
在尝试了不同的电子表格后,我能够回答这个问题。
在未对地址进行操作的情况下(如我先前的示例 5 * $ F $ 7 )(例如VLookup中的IF语句),将值返回为ExcelAddress非常有用。
如果有操作员,您将需要返回单元格的内容。 我修改了EPPlus代码,现在检查是否有任何运算符将公式中的术语分开
public override CompileResult Compile()
{
if (ParentIsLookupFunction &&
Operator == null &&
(Prev == null || Prev.Operator == null))
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}