はじめに
こちらの記事でClosedXMLの使い方をまとめてみましたが、うまくセルの値が取得できずはまったことがあったので、まとめ。
対応していない関数がある
Excelのセルから値を取得するときは、ClosedXMLのメソッドValueで取得します。このときセルに関数が設定されていると、関数の計算結果が取得できます。
var workBook = new XLWorkbook("C:\\wk\\sample.xlsx");
var workSheet = workBook.Worksheet("sheet1");
var cellVal = workSheet.Cell(1, 1).Value;
正しく取得できるケース
例えば、以下の例
C1セルに関数:SUM(A1:B1)を設定します。計算結果は「3」。
で、ClosedXMLでC1セルの値を取得
var workBook = new XLWorkbook("C:\\wk\\sample.xlsx");
var workSheet = workBook.Worksheet("sheet1");
Console.WriteLine($"C1 = {workSheet.Cell(1, 3).Value}");
結果は
C1 = 3
関数の計算結果が取得できます。
失敗するケース
C3セルの計算にINDIRECT関数を使用します。→→SUM(INDIRECT("A1:B1"))
結果は以下のようなエラーとなります。
Unhandled exception. ClosedXML.Excel.CalcEngine.Exceptions.NameNotRecognizedException: The identifier `INDIRECT` was not recognised.
以下ClosedXMLのソースを見ると、全ての関数に対応しているわけでは無いようです。
詳しくは追っていませんが、プログラムで関数を解釈して結果を返しているものと思われます。
補足
こちらのソースで何度か試しているときに、エクセル側の計算式の変更、ブックの変更などのタイミングにより、うまく動くこともあったり、エラーになることもありました。法則がちょっとよくわかってませんが、エラーが出力されることがあるのは確かです。
対策
try/catchでValue取得でエラーとなる場合、FormulaA1でセルに設定している関数を取得するようにして回避してみました。
try
{
Console.WriteLine($"C1 = {workSheet.Cell(1, 3).Value}");
}catch
{
Console.WriteLine($"C1(関数) = {workSheet.Cell(1, 3).FormulaA1}");
}
結果は
C1 = SUM(INDIRECT("A1:B1"))