EPPlus 在返回 ValueError 的 VLookup 函数中将一个范围乘以一个常量
EPPlus multiplying a range by a constant inside a VLookup function returning ValueError
我在 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+$F1+$K-$F-1,Sheet2!$A:$T3,5*$F+2*$B+$B-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 文件的编译函数中,ParentIsLookupFunction 布尔值控制单元格是被评估还是保留为地址。
public override CompileResult Compile()
{
if (ParentIsLookupFunction)
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}
我已将我的代码版本修改为
public override CompileResult Compile()
{
return CompileRangeValues();
}
正如问题顶部所说,我想知道的是你为什么要 return ExcelAddress CompileResult,它显然是有原因的,我不想破坏一些我电子表格中的其他计算。
我可以确认至少对于这个计算它现在工作正常。
几年前写过EPPlus的公式引擎,最近没怎么搞这个项目。如果我没记错的话,在某些情况下您不想编译表达式中的 excel 地址,而是将其传递给执行函数。您是否尝试过 运行 单元测试?公式引擎经过数百次测试,测试结果可以提供一些指导。
在尝试了不同的电子表格后,我能够回答这个问题。
如果地址未像我之前的示例那样进行操作,则将值作为 ExcelAddress 返回很有用 5*$F$7 例如VLookup.
如果有运算符,您将需要 return 单元格的内容。
我修改了 EPPlus 代码,现在检查公式
中的任何分隔项的运算符
public override CompileResult Compile()
{
if (ParentIsLookupFunction &&
Operator == null &&
(Prev == null || Prev.Operator == null))
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}
我在 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+$F1+$K-$F-1,Sheet2!$A:$T3,5*$F+2*$B+$B-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 文件的编译函数中,ParentIsLookupFunction 布尔值控制单元格是被评估还是保留为地址。
public override CompileResult Compile()
{
if (ParentIsLookupFunction)
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}
我已将我的代码版本修改为
public override CompileResult Compile()
{
return CompileRangeValues();
}
正如问题顶部所说,我想知道的是你为什么要 return ExcelAddress CompileResult,它显然是有原因的,我不想破坏一些我电子表格中的其他计算。
我可以确认至少对于这个计算它现在工作正常。
几年前写过EPPlus的公式引擎,最近没怎么搞这个项目。如果我没记错的话,在某些情况下您不想编译表达式中的 excel 地址,而是将其传递给执行函数。您是否尝试过 运行 单元测试?公式引擎经过数百次测试,测试结果可以提供一些指导。
在尝试了不同的电子表格后,我能够回答这个问题。
如果地址未像我之前的示例那样进行操作,则将值作为 ExcelAddress 返回很有用 5*$F$7 例如VLookup.
如果有运算符,您将需要 return 单元格的内容。 我修改了 EPPlus 代码,现在检查公式
中的任何分隔项的运算符 public override CompileResult Compile()
{
if (ParentIsLookupFunction &&
Operator == null &&
(Prev == null || Prev.Operator == null))
{
return new CompileResult(ExpressionString, DataType.ExcelAddress);
}
else
{
return CompileRangeValues();
}
}